LWG 2996 add rvalue overloads for shared_ptr aliasing and casting

* doc/xml/manual/intro.xml: Document LWG DR 2996 change.
	* doc/html/*: Regenerate.
	* include/bits/shared_ptr.h (shared_ptr(shared_ptr&&, T*)): Add
	rvalue aliasing constructor.
	(static_pointer_cast, const_pointer, dynamic_pointer_cast)
	(reinterpret_pointer_cast): Add overloads taking rvalues.
	* include/bits/shared_ptr_base.h (__shared_ptr(__shared_ptr&&, T*)):
	Add rvalue aliasing constructor.
	* testsuite/20_util/shared_ptr/casts/1.cc: Change "compile" test to
	"run" and check return values as well as types.
	* testsuite/20_util/shared_ptr/casts/reinterpret.cc: Likewise.
	* testsuite/20_util/shared_ptr/casts/rval.cc: New test.
	* testsuite/20_util/shared_ptr/cons/alias-rval.cc: New test.
	* testsuite/20_util/shared_ptr/cons/alias.cc: Remove unused return
	values.

From-SVN: r271583
This commit is contained in:
Jonathan Wakely 2019-05-23 22:41:02 +01:00 committed by Jonathan Wakely
parent 9a0af7e3fb
commit fb3fc4bded
11 changed files with 416 additions and 29 deletions

View File

@ -1,5 +1,21 @@
2019-05-23 Jonathan Wakely <jwakely@redhat.com>
* doc/xml/manual/intro.xml: Document LWG DR 2996 change.
* doc/html/*: Regenerate.
* include/bits/shared_ptr.h (shared_ptr(shared_ptr&&, T*)): Add
rvalue aliasing constructor.
(static_pointer_cast, const_pointer, dynamic_pointer_cast)
(reinterpret_pointer_cast): Add overloads taking rvalues.
* include/bits/shared_ptr_base.h (__shared_ptr(__shared_ptr&&, T*)):
Add rvalue aliasing constructor.
* testsuite/20_util/shared_ptr/casts/1.cc: Change "compile" test to
"run" and check return values as well as types.
* testsuite/20_util/shared_ptr/casts/reinterpret.cc: Likewise.
* testsuite/20_util/shared_ptr/casts/rval.cc: New test.
* testsuite/20_util/shared_ptr/cons/alias-rval.cc: New test.
* testsuite/20_util/shared_ptr/cons/alias.cc: Remove unused return
values.
* doc/xml/manual/evolution.xml: Document LWG DR 2921 change.
* doc/xml/manual/intro.xml: Likewise.
* include/std/future (__create_task_state): Add default arguments

View File

@ -393,4 +393,7 @@ now defaults to zero.
<code class="filename">&lt;experimental/timer&gt;</code>.
</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a id="api.rel_101"></a><code class="constant">10</code></h3></div></div></div><p> Deprecated features removed:
</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"> Profile Mode </li><li class="listitem"><code class="classname">__gnu_cxx::array_allocator</code></li></ul></div><p>
</p><p>
The <code class="classname">std::packaged_task</code> constructors taking
an allocator argument are only defined for C++11 and C++14.
</p></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="abi.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="appendix_porting.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="backwards.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">ABI Policy and Guidelines </td><td width="20%" align="center"><a accesskey="h" href="../index.html">Home</a></td><td width="40%" align="right" valign="top"> Backwards Compatibility</td></tr></table></div></body></html>

View File

@ -565,11 +565,21 @@
<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><a id="manual.bugs.dr2921"></a><span class="term"><a class="link" href="http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2921" target="_top">2921</a>:
<span class="emphasis"><em><code class="code">packaged_task</code> and type-erased allocators
</em></span>
</span></dt><dd><p>For C++17 mode, remove the constructors taking
an allocator argument.
</p></dd><dt><a id="manual.bugs.dr2942"></a><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><dt><a id="manual.bugs.dr2996"></a><span class="term"><a class="link" href="http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2996" target="_top">2996</a>:
<span class="emphasis"><em>Missing rvalue overloads for
<code class="code">shared_ptr</code> operations
</em></span>
</span></dt><dd><p>Add additional constructor and cast overloads.
</p></dd><dt><a id="manual.bugs.dr2993"></a><span class="term"><a class="link" href="http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2993" target="_top">2993</a>:
<span class="emphasis"><em><code class="code">reference_wrapper&lt;T&gt;</code> conversion from <code class="code">T&amp;&amp;</code>
</em></span>

View File

@ -1237,6 +1237,14 @@ requirements of the license of GCC.
<listitem><para>Add noexcept.
</para></listitem></varlistentry>
<varlistentry xml:id="manual.bugs.dr2996"><term><link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="&DR;#2996">2996</link>:
<emphasis>Missing rvalue overloads for
<code>shared_ptr</code> operations
</emphasis>
</term>
<listitem><para>Add additional constructor and cast overloads.
</para></listitem></varlistentry>
<varlistentry xml:id="manual.bugs.dr2993"><term><link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="&DR;#2993">2993</link>:
<emphasis><code>reference_wrapper&lt;T&gt;</code> conversion from <code>T&amp;&amp;</code>
</emphasis>

View File

@ -235,17 +235,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
// Aliasing constructor
/**
* @brief Constructs a %shared_ptr instance that stores @a __p
* and shares ownership with @a __r.
* @param __r A %shared_ptr.
* @param __p A pointer that will remain valid while @a *__r is valid.
* @post get() == __p && use_count() == __r.use_count()
* @brief Constructs a `shared_ptr` instance that stores `__p`
* and shares ownership with `__r`.
* @param __r A `shared_ptr`.
* @param __p A pointer that will remain valid while `*__r` is valid.
* @post `get() == __p && use_count() == __r.use_count()`
*
* This can be used to construct a @c shared_ptr to a sub-object
* of an object managed by an existing @c shared_ptr.
* This can be used to construct a `shared_ptr` to a sub-object
* of an object managed by an existing `shared_ptr`. The complete
* object will remain valid while any `shared_ptr` owns it, even
* if they don't store a pointer to the complete object.
*
* @code
* shared_ptr< pair<int,int> > pii(new pair<int,int>());
* shared_ptr<pair<int,int>> pii(new pair<int,int>());
* shared_ptr<int> pi(pii, &pii->first);
* assert(pii.use_count() == 2);
* @endcode
@ -254,6 +256,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
shared_ptr(const shared_ptr<_Yp>& __r, element_type* __p) noexcept
: __shared_ptr<_Tp>(__r, __p) { }
#if __cplusplus > 201703L
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 2996. Missing rvalue overloads for shared_ptr operations
/**
* @brief Constructs a `shared_ptr` instance that stores `__p`
* and shares ownership with `__r`.
* @param __r A `shared_ptr`.
* @param __p A pointer that will remain valid while `*__r` is valid.
* @post `get() == __p && !__r.use_count() && !__r.get()`
*
* This can be used to construct a `shared_ptr` to a sub-object
* of an object managed by an existing `shared_ptr`. The complete
* object will remain valid while any `shared_ptr` owns it, even
* if they don't store a pointer to the complete object.
*
* @code
* shared_ptr<pair<int,int>> pii(new pair<int,int>());
* shared_ptr<int> pi1(pii, &pii->first);
* assert(pii.use_count() == 2);
* shared_ptr<int> pi2(std::move(pii), &pii->second);
* assert(pii.use_count() == 0);
* @endcode
*/
template<typename _Yp>
shared_ptr(shared_ptr<_Yp>&& __r, element_type* __p) noexcept
: __shared_ptr<_Tp>(std::move(__r), __p) { }
#endif
/**
* @brief If @a __r is empty, constructs an empty %shared_ptr;
* otherwise construct a %shared_ptr that shares ownership
@ -568,7 +597,53 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
using _Sp = shared_ptr<_Tp>;
return _Sp(__r, reinterpret_cast<typename _Sp::element_type*>(__r.get()));
}
#endif
#if __cplusplus > 201703L
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 2996. Missing rvalue overloads for shared_ptr operations
/// Convert type of `shared_ptr` rvalue, via `static_cast`
template<typename _Tp, typename _Up>
inline shared_ptr<_Tp>
static_pointer_cast(shared_ptr<_Up>&& __r) noexcept
{
using _Sp = shared_ptr<_Tp>;
return _Sp(std::move(__r),
static_cast<typename _Sp::element_type*>(__r.get()));
}
/// Convert type of `shared_ptr` rvalue, via `const_cast`
template<typename _Tp, typename _Up>
inline shared_ptr<_Tp>
const_pointer_cast(shared_ptr<_Up>&& __r) noexcept
{
using _Sp = shared_ptr<_Tp>;
return _Sp(std::move(__r),
const_cast<typename _Sp::element_type*>(__r.get()));
}
/// Convert type of `shared_ptr` rvalue, via `dynamic_cast`
template<typename _Tp, typename _Up>
inline shared_ptr<_Tp>
dynamic_pointer_cast(shared_ptr<_Up>&& __r) noexcept
{
using _Sp = shared_ptr<_Tp>;
if (auto* __p = dynamic_cast<typename _Sp::element_type*>(__r.get()))
return _Sp(std::move(__r), __p);
return _Sp();
}
/// Convert type of `shared_ptr` rvalue, via `reinterpret_cast`
template<typename _Tp, typename _Up>
inline shared_ptr<_Tp>
reinterpret_pointer_cast(shared_ptr<_Up>&& __r) noexcept
{
using _Sp = shared_ptr<_Tp>;
return _Sp(std::move(__r),
reinterpret_cast<typename _Sp::element_type*>(__r.get()));
}
#endif // C++20
#endif // C++17
// @}

View File

@ -1158,12 +1158,23 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
: _M_ptr(0), _M_refcount(__p, std::move(__d), std::move(__a))
{ }
// Aliasing constructor
template<typename _Yp>
__shared_ptr(const __shared_ptr<_Yp, _Lp>& __r,
element_type* __p) noexcept
: _M_ptr(__p), _M_refcount(__r._M_refcount) // never throws
{ }
// Aliasing constructor
template<typename _Yp>
__shared_ptr(__shared_ptr<_Yp, _Lp>&& __r,
element_type* __p) noexcept
: _M_ptr(__p), _M_refcount()
{
_M_refcount._M_swap(__r._M_refcount);
__r._M_ptr = 0;
}
__shared_ptr(const __shared_ptr&) noexcept = default;
__shared_ptr& operator=(const __shared_ptr&) noexcept = default;
~__shared_ptr() = default;

View File

@ -1,4 +1,4 @@
// { dg-do compile { target c++11 } }
// { dg-do run { target c++11 } }
// Copyright (C) 2006-2019 Free Software Foundation, Inc.
//
@ -20,12 +20,14 @@
// 20.6.6.2.10 shared_ptr casts [util.smartptr.shared.cast]
#include <memory>
#include <testsuite_hooks.h>
#include <testsuite_tr1.h>
struct MyP { virtual ~MyP() { }; };
struct MyDP : MyP { };
int main()
void
test01()
{
using __gnu_test::check_ret_type;
using std::shared_ptr;
@ -37,7 +39,50 @@ int main()
shared_ptr<const int> spci;
shared_ptr<MyP> spa;
check_ret_type<shared_ptr<void> >(static_pointer_cast<void>(spd));
check_ret_type<shared_ptr<int> >(const_pointer_cast<int>(spci));
check_ret_type<shared_ptr<MyDP> >(static_pointer_cast<MyDP>(spa));
check_ret_type<shared_ptr<void>>(static_pointer_cast<void>(spd));
check_ret_type<shared_ptr<int>>(const_pointer_cast<int>(spci));
check_ret_type<shared_ptr<MyDP>>(dynamic_pointer_cast<MyDP>(spa));
}
void
test02()
{
using std::shared_ptr;
using std::static_pointer_cast;
using std::const_pointer_cast;
using std::dynamic_pointer_cast;
int* ptr = new int(1);
shared_ptr<const void> pcv(ptr);
auto pci = static_pointer_cast<const int>(pcv);
VERIFY(pci.use_count() == 2);
VERIFY(pcv.use_count() == 2);
VERIFY(pci.get() == ptr);
VERIFY(pcv.get() == ptr);
auto pi = const_pointer_cast<int>(pci);
VERIFY(pi.use_count() == 3);
VERIFY(pcv.use_count() == 3);
VERIFY(pi.get() == ptr);
VERIFY(pci.get() == ptr);
MyP* pptr = new MyP;
shared_ptr<MyP> pp(pptr);
auto pdp = dynamic_pointer_cast<MyDP>(pp);
VERIFY(pp.use_count() == 1);
VERIFY(pdp.use_count() == 0);
VERIFY(pdp.get() == nullptr);
VERIFY(pp.get() == pptr);
pptr = new MyDP;
pp.reset(pptr);
pdp = dynamic_pointer_cast<MyDP>(pp);
VERIFY(pp.use_count() == 2);
VERIFY(pdp.use_count() == 2);
VERIFY(pdp.get() == pptr);
VERIFY(pp.get() == pptr);
}
int main()
{
test01();
test02();
}

View File

@ -1,5 +1,5 @@
// { dg-options "-std=gnu++17" }
// { dg-do compile { target c++17 } }
// { dg-do run { target c++17 } }
// Copyright (C) 2016-2019 Free Software Foundation, Inc.
//
@ -21,12 +21,14 @@
// 20.11.2.2.9 shared_ptr casts [util.smartptr.shared.cast]
#include <memory>
#include <testsuite_hooks.h>
#include <testsuite_tr1.h>
struct MyP { virtual ~MyP() { }; };
struct MyDP : MyP { };
int main()
void
test01()
{
using __gnu_test::check_ret_type;
using std::shared_ptr;
@ -36,7 +38,28 @@ int main()
shared_ptr<const int> spci;
shared_ptr<MyP> spa;
check_ret_type<shared_ptr<void> >(reinterpret_pointer_cast<void>(spd));
check_ret_type<shared_ptr<const short> >(reinterpret_pointer_cast<const short>(spci));
check_ret_type<shared_ptr<MyDP> >(reinterpret_pointer_cast<MyDP>(spa));
check_ret_type<shared_ptr<void>>(reinterpret_pointer_cast<void>(spd));
check_ret_type<shared_ptr<const short>>(reinterpret_pointer_cast<const short>(spci));
check_ret_type<shared_ptr<MyDP>>(reinterpret_pointer_cast<MyDP>(spa));
}
void
test02()
{
using std::shared_ptr;
using std::reinterpret_pointer_cast;
int* ptr = new int(2);
shared_ptr<int> pi(ptr);
auto pl = reinterpret_pointer_cast<long>(pi);
VERIFY(pi.use_count() == 2);
VERIFY(pl.use_count() == 2);
VERIFY(pi.get() == ptr);
VERIFY(reinterpret_cast<int*>(pl.get()) == ptr);
}
int main()
{
test01();
test02();
}

View File

@ -0,0 +1,101 @@
// { dg-options "-std=gnu++2a" }
// { dg-do run { target c++2a } }
// Copyright (C) 2019 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/>.
// shared_ptr casts [util.smartptr.shared.cast]
#include <memory>
#include <testsuite_hooks.h>
#include <testsuite_tr1.h>
struct MyP { virtual ~MyP() { }; };
struct MyDP : MyP { };
void test01()
{
using __gnu_test::check_ret_type;
using std::shared_ptr;
using std::static_pointer_cast;
using std::const_pointer_cast;
using std::dynamic_pointer_cast;
using std::reinterpret_pointer_cast;
shared_ptr<double> spd;
shared_ptr<const int> spci;
shared_ptr<MyP> spa;
check_ret_type<shared_ptr<void>>(static_pointer_cast<void>(std::move(spd)));
check_ret_type<shared_ptr<int>>(const_pointer_cast<int>(std::move(spci)));
check_ret_type<shared_ptr<MyDP>>(dynamic_pointer_cast<MyDP>(std::move(spa)));
check_ret_type<shared_ptr<void>>(reinterpret_pointer_cast<void>(std::move(spd)));
check_ret_type<shared_ptr<const short>>(reinterpret_pointer_cast<const short>(std::move(spci)));
check_ret_type<shared_ptr<MyDP>>(reinterpret_pointer_cast<MyDP>(std::move(spa)));
}
void
test02()
{
using std::shared_ptr;
using std::static_pointer_cast;
using std::const_pointer_cast;
using std::dynamic_pointer_cast;
using std::reinterpret_pointer_cast;
int* ptr = new int(1);
shared_ptr<const void> pcv(ptr);
auto pci = static_pointer_cast<const int>(std::move(pcv));
VERIFY(pci.use_count() == 1);
VERIFY(pcv.use_count() == 0);
VERIFY(pci.get() == ptr);
VERIFY(pcv.get() == nullptr);
auto pi = const_pointer_cast<int>(std::move(pci));
VERIFY(pi.use_count() == 1);
VERIFY(pci.use_count() == 0);
VERIFY(pi.get() == ptr);
VERIFY(pci.get() == nullptr);
MyP* pptr = new MyP;
shared_ptr<MyP> pp(pptr);
auto pdp = dynamic_pointer_cast<MyDP>(std::move(pp));
VERIFY(pdp.use_count() == 0);
VERIFY(pp.use_count() == 1);
VERIFY(pdp.get() == nullptr);
VERIFY(pp.get() == pptr);
pptr = new MyDP;
pp.reset(pptr);
pdp = dynamic_pointer_cast<MyDP>(std::move(pp));
VERIFY(pdp.use_count() == 1);
VERIFY(pp.use_count() == 0);
VERIFY(pdp.get() == pptr);
VERIFY(pp.get() == nullptr);
ptr = new int(2);
pi.reset(ptr);
auto pl = reinterpret_pointer_cast<long>(std::move(pi));
VERIFY(pl.use_count() == 1);
VERIFY(pi.use_count() == 0);
VERIFY(reinterpret_cast<int*>(pl.get()) == ptr);
VERIFY(pi.get() == nullptr);
}
int main()
{
test01();
test02();
}

View File

@ -0,0 +1,101 @@
// { dg-options "-std=gnu++2a" }
// { dg-do run { target c++2a } }
// Copyright (C) 2019 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/>.
// Template class shared_ptr [util.smartptr.shared]
#include <memory>
#include <testsuite_hooks.h>
struct A
{
A() : i() { }
virtual ~A() { }
int i;
};
struct B : A
{
B() : A(), a() { }
virtual ~B() { }
A a;
};
void deletefunc(A* p) { delete p; }
// 20.6.6.2.1 shared_ptr constructors [util.smartptr.shared.const]
// Aliasing constructors
void
test01()
{
bool test = true;
std::shared_ptr<A> a;
std::shared_ptr<bool> b1(std::move(a), &test);
VERIFY( b1.use_count() == 0 );
VERIFY( b1.get() == &test );
VERIFY( a.use_count() == 0 );
VERIFY( a == nullptr );
std::shared_ptr<bool> b2(b1);
VERIFY( b2.use_count() == 0 );
VERIFY( b1 == b2 );
}
void
test02()
{
std::shared_ptr<A> a(new A);
std::shared_ptr<int> i1(std::move(a), &a->i);
VERIFY( i1.use_count() == 1 );
VERIFY( i1 != nullptr );
VERIFY( a.use_count() == 0 );
VERIFY( a == nullptr );
std::shared_ptr<int> i2(i1);
VERIFY( i2.use_count() == 2 );
VERIFY( i2.get() == &a->i );
}
void
test03()
{
std::shared_ptr<B> b1(new B);
std::shared_ptr<B> b2(b1);
std::shared_ptr<A> a1(std::move(b1), b1.get());
std::shared_ptr<A> a2(b2, &b2->a);
VERIFY( a2.use_count() == 2 );
VERIFY( a1 != nullptr );
VERIFY( a2 != nullptr );
VERIFY( a1 != a2 );
VERIFY( b1.use_count() == 0 );
VERIFY( b2.use_count() == 0 );
VERIFY( b1 == nullptr );
VERIFY( b2 == nullptr );
}
int
main()
{
test01();
test02();
test03();
}

View File

@ -42,7 +42,8 @@ void deletefunc(A* p) { delete p; }
// Aliasing constructors
int test01()
void
test01()
{
bool test = true;
@ -55,11 +56,9 @@ int test01()
std::shared_ptr<bool> b2(b1);
VERIFY( b2.use_count() == 0 );
VERIFY( b1.get() == b2.get() );
return 0;
}
int
void
test02()
{
std::shared_ptr<A> a(new A);
@ -69,11 +68,9 @@ test02()
std::shared_ptr<int> i2(i1);
VERIFY( i2.use_count() == 3 );
VERIFY( i2.get() == &a->i );
return 0;
}
int
void
test03()
{
std::shared_ptr<B> b(new B);
@ -89,8 +86,6 @@ test03()
a3 = a2;
VERIFY( a3.get() == &b->a );
return 0;
}
int
@ -99,5 +94,4 @@ main()
test01();
test02();
test03();
return 0;
}