Support move-only deleters in std::shared_ptr (LWG 2802)

Backport from mainline
2017-06-09  Jonathan Wakely  <jwakely@redhat.com>

	* doc/xml/manual/intro.xml: Document LWG 2802, 2873 and 2942 changes.
	* include/bits/shared_ptr.h (shared_ptr): Use rvalues for deleters
	(LWG 2802).
	* include/bits/shared_ptr_base.h (_Sp_ebo_helper, _Sp_counted_deleter
	(_Sp_counted_deleter::_Impl, __shared_count, __shared_ptr): Likewise.
	* testsuite/20_util/shared_ptr/cons/lwg2802.cc: New.

From-SVN: r250541
This commit is contained in:
Jonathan Wakely 2017-07-25 19:05:25 +01:00 committed by Jonathan Wakely
parent dea4c7435c
commit 371868a847
6 changed files with 113 additions and 13 deletions

View File

@ -1,5 +1,15 @@
2017-07-25 Jonathan Wakely <jwakely@redhat.com>
Backport from mainline
2017-06-09 Jonathan Wakely <jwakely@redhat.com>
* doc/xml/manual/intro.xml: Document LWG 2802, 2873 and 2942 changes.
* include/bits/shared_ptr.h (shared_ptr): Use rvalues for deleters
(LWG 2802).
* include/bits/shared_ptr_base.h (_Sp_ebo_helper, _Sp_counted_deleter
(_Sp_counted_deleter::_Impl, __shared_count, __shared_ptr): Likewise.
* testsuite/20_util/shared_ptr/cons/lwg2802.cc: New.
Backport from mainline
2017-06-05 Jonathan Wakely <jwakely@redhat.com>

View File

@ -504,4 +504,18 @@
</em></span>
</span></dt><dd><p>Remove special handling for <code class="code">reference_wrapper</code>
arguments and store them directly as the target object.
</p></dd><dt><span class="term"><a class="link" href="http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2802" target="_top">2802</a>:
<span class="emphasis"><em>Add noexcept to several <code class="code">shared_ptr</code> related
functions
</em></span>
</span></dt><dd><p>Add noexcept.
</p></dd><dt><span class="term"><a class="link" href="http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2873" target="_top">2873</a>:
<span class="emphasis"><em><code class="code">shared_ptr</code> constructor requirements for a deleter
</em></span>
</span></dt><dd><p>Use rvalues for deleters.
</p></dd><dt><span class="term"><a class="link" href="http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2942" target="_top">2942</a>:
<span class="emphasis"><em>LWG 2873's resolution missed
<code class="code">weak_ptr::owner_before</code>
</em></span>
</span></dt><dd><p>Add noexcept.
</p></dd></dl></div></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="license.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="status.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="setup.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">License </td><td width="20%" align="center"><a accesskey="h" href="../index.html">Home</a></td><td width="40%" align="right" valign="top"> Chapter 2. Setup</td></tr></table></div></body></html>

View File

@ -1119,6 +1119,29 @@ requirements of the license of GCC.
arguments and store them directly as the target object.
</para></listitem></varlistentry>
<varlistentry><term><link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="&DR;#2802">2802</link>:
<emphasis>Add noexcept to several <code>shared_ptr</code> related
functions
</emphasis>
</term>
<listitem><para>Add noexcept.
</para></listitem></varlistentry>
<varlistentry><term><link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="&DR;#2873">2873</link>:
<emphasis><code>shared_ptr</code> constructor requirements for a deleter
</emphasis>
</term>
<listitem><para>Use rvalues for deleters.
</para></listitem></varlistentry>
<varlistentry><term><link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="&DR;#2942">2942</link>:
<emphasis>LWG 2873's resolution missed
<code>weak_ptr::owner_before</code>
</emphasis>
</term>
<listitem><para>Add noexcept.
</para></listitem></varlistentry>
</variablelist>
</section>

View File

@ -144,7 +144,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _Yp, typename _Deleter,
typename = _Constructible<_Yp*, _Deleter>>
shared_ptr(_Yp* __p, _Deleter __d)
: __shared_ptr<_Tp>(__p, __d) { }
: __shared_ptr<_Tp>(__p, std::move(__d)) { }
/**
* @brief Construct a %shared_ptr that owns a null pointer
@ -161,7 +161,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
*/
template<typename _Deleter>
shared_ptr(nullptr_t __p, _Deleter __d)
: __shared_ptr<_Tp>(__p, __d) { }
: __shared_ptr<_Tp>(__p, std::move(__d)) { }
/**
* @brief Construct a %shared_ptr that owns the pointer @a __p
@ -181,7 +181,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _Yp, typename _Deleter, typename _Alloc,
typename = _Constructible<_Yp*, _Deleter, _Alloc>>
shared_ptr(_Yp* __p, _Deleter __d, _Alloc __a)
: __shared_ptr<_Tp>(__p, __d, std::move(__a)) { }
: __shared_ptr<_Tp>(__p, std::move(__d), std::move(__a)) { }
/**
* @brief Construct a %shared_ptr that owns a null pointer
@ -200,7 +200,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
*/
template<typename _Deleter, typename _Alloc>
shared_ptr(nullptr_t __p, _Deleter __d, _Alloc __a)
: __shared_ptr<_Tp>(__p, __d, std::move(__a)) { }
: __shared_ptr<_Tp>(__p, std::move(__d), std::move(__a)) { }
// Aliasing constructor

View File

@ -411,6 +411,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
struct _Sp_ebo_helper<_Nm, _Tp, true> : private _Tp
{
explicit _Sp_ebo_helper(const _Tp& __tp) : _Tp(__tp) { }
explicit _Sp_ebo_helper(_Tp&& __tp) : _Tp(std::move(__tp)) { }
static _Tp&
_S_get(_Sp_ebo_helper& __eboh) { return static_cast<_Tp&>(__eboh); }
@ -421,6 +422,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
struct _Sp_ebo_helper<_Nm, _Tp, false>
{
explicit _Sp_ebo_helper(const _Tp& __tp) : _M_tp(__tp) { }
explicit _Sp_ebo_helper(_Tp&& __tp) : _M_tp(std::move(__tp)) { }
static _Tp&
_S_get(_Sp_ebo_helper& __eboh)
@ -441,7 +443,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
public:
_Impl(_Ptr __p, _Deleter __d, const _Alloc& __a) noexcept
: _M_ptr(__p), _Del_base(__d), _Alloc_base(__a)
: _M_ptr(__p), _Del_base(std::move(__d)), _Alloc_base(__a)
{ }
_Deleter& _M_del() noexcept { return _Del_base::_S_get(*this); }
@ -455,11 +457,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
// __d(__p) must not throw.
_Sp_counted_deleter(_Ptr __p, _Deleter __d) noexcept
: _M_impl(__p, __d, _Alloc()) { }
: _M_impl(__p, std::move(__d), _Alloc()) { }
// __d(__p) must not throw.
_Sp_counted_deleter(_Ptr __p, _Deleter __d, const _Alloc& __a) noexcept
: _M_impl(__p, __d, __a) { }
: _M_impl(__p, std::move(__d), __a) { }
~_Sp_counted_deleter() noexcept { }
@ -1083,7 +1085,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _Yp, typename _Deleter, typename = _SafeConv<_Yp>>
__shared_ptr(_Yp* __p, _Deleter __d)
: _M_ptr(__p), _M_refcount(__p, __d)
: _M_ptr(__p), _M_refcount(__p, std::move(__d))
{
static_assert(__is_invocable<_Deleter&, _Yp*&>::value,
"deleter expression d(p) is well-formed");
@ -1093,7 +1095,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _Yp, typename _Deleter, typename _Alloc,
typename = _SafeConv<_Yp>>
__shared_ptr(_Yp* __p, _Deleter __d, _Alloc __a)
: _M_ptr(__p), _M_refcount(__p, __d, std::move(__a))
: _M_ptr(__p), _M_refcount(__p, std::move(__d), std::move(__a))
{
static_assert(__is_invocable<_Deleter&, _Yp*&>::value,
"deleter expression d(p) is well-formed");
@ -1102,12 +1104,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _Deleter>
__shared_ptr(nullptr_t __p, _Deleter __d)
: _M_ptr(0), _M_refcount(__p, __d)
: _M_ptr(0), _M_refcount(__p, std::move(__d))
{ }
template<typename _Deleter, typename _Alloc>
__shared_ptr(nullptr_t __p, _Deleter __d, _Alloc __a)
: _M_ptr(0), _M_refcount(__p, __d, std::move(__a))
: _M_ptr(0), _M_refcount(__p, std::move(__d), std::move(__a))
{ }
template<typename _Yp>
@ -1244,12 +1246,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _Yp, typename _Deleter>
_SafeConv<_Yp>
reset(_Yp* __p, _Deleter __d)
{ __shared_ptr(__p, __d).swap(*this); }
{ __shared_ptr(__p, std::move(__d)).swap(*this); }
template<typename _Yp, typename _Deleter, typename _Alloc>
_SafeConv<_Yp>
reset(_Yp* __p, _Deleter __d, _Alloc __a)
{ __shared_ptr(__p, __d, std::move(__a)).swap(*this); }
{ __shared_ptr(__p, std::move(__d), std::move(__a)).swap(*this); }
element_type*
get() const noexcept

View File

@ -0,0 +1,51 @@
// Copyright (C) 2017 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the
// terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3, or (at your option)
// any later version.
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License along
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
// { dg-do compile { target c++11 } }
#include <memory>
// LWG 2802. shared_ptr constructor requirements for a deleter
struct D
{
D() { }
D(D&&) { }
void operator()(int* p) const { delete p; }
};
std::allocator<int> a;
std::shared_ptr<int> s1((int*)nullptr, D());
std::shared_ptr<int> s2((int*)nullptr, D(), a);
std::shared_ptr<int> s3(nullptr, D());
std::shared_ptr<int> s4(nullptr, D(), a);
void test01()
{
s1.reset((int*)nullptr, D());
s1.reset((int*)nullptr, D(), a);
}
struct D2 final
{
D2() { }
D2(D2&&) { }
void operator()(int* p) const { delete p; }
};
std::shared_ptr<int> s5(nullptr, D2());