[libc++] Make shared_ptr move unique_ptr's deleter

Addresses LWG 3548 which mandates that when shared_ptr is being constructed from a unique_ptr, the unique_ptr's deleter should be moved and not copied.

Reviewed By: #libc, philnik, EricWF

Differential Revision: https://reviews.llvm.org/D119159
This commit is contained in:
Asher Mancinelli 2022-03-18 11:36:25 -06:00
parent 8f108c32bc
commit 34538dba9b
3 changed files with 46 additions and 10 deletions

View File

@ -90,7 +90,7 @@
`3543 <https://wg21.link/LWG3543>`__,"Definition of when ``counted_iterators`` refer to the same sequence isn't quite right","June 2021","|Nothing To Do|","","|ranges|"
`3544 <https://wg21.link/LWG3544>`__,"``format-arg-store::args`` is unintentionally not exposition-only","June 2021","|Complete|","14.0","|format|"
`3546 <https://wg21.link/LWG3546>`__,"``common_iterator``'s postfix-proxy is not quite right","June 2021","","","|ranges|"
`3548 <https://wg21.link/LWG3548>`__,"``shared_ptr`` construction from ``unique_ptr`` should move (not copy) the deleter","June 2021","",""
`3548 <https://wg21.link/LWG3548>`__,"``shared_ptr`` construction from ``unique_ptr`` should move (not copy) the deleter","June 2021","|Complete|","15.0"
`3549 <https://wg21.link/LWG3549>`__,"``view_interface`` is overspecified to derive from ``view_base``","June 2021","|Complete|","14.0","|ranges|"
`3551 <https://wg21.link/LWG3551>`__,"``borrowed_{iterator,subrange}_t`` are overspecified","June 2021","|Nothing To Do|","","|ranges|"
`3552 <https://wg21.link/LWG3552>`__,"Parallel specialized memory algorithms should require forward iterators","June 2021","",""

Can't render this file because it has a wrong number of fields in line 2.

View File

@ -457,7 +457,7 @@ public:
explicit shared_ptr(_Yp* __p) : __ptr_(__p) {
unique_ptr<_Yp> __hold(__p);
typedef typename __shared_ptr_default_allocator<_Yp>::type _AllocT;
typedef __shared_ptr_pointer<_Yp*, __shared_ptr_default_delete<_Tp, _Yp>, _AllocT > _CntrlBlk;
typedef __shared_ptr_pointer<_Yp*, __shared_ptr_default_delete<_Tp, _Yp>, _AllocT> _CntrlBlk;
__cntrl_ = new _CntrlBlk(__p, __shared_ptr_default_delete<_Tp, _Yp>(), _AllocT());
__hold.release();
__enable_weak_this(__p, __p);
@ -473,7 +473,7 @@ public:
{
#endif // _LIBCPP_NO_EXCEPTIONS
typedef typename __shared_ptr_default_allocator<_Yp>::type _AllocT;
typedef __shared_ptr_pointer<_Yp*, _Dp, _AllocT > _CntrlBlk;
typedef __shared_ptr_pointer<_Yp*, _Dp, _AllocT> _CntrlBlk;
#ifndef _LIBCPP_CXX03_LANG
__cntrl_ = new _CntrlBlk(__p, _VSTD::move(__d), _AllocT());
#else
@ -532,7 +532,7 @@ public:
{
#endif // _LIBCPP_NO_EXCEPTIONS
typedef typename __shared_ptr_default_allocator<_Tp>::type _AllocT;
typedef __shared_ptr_pointer<nullptr_t, _Dp, _AllocT > _CntrlBlk;
typedef __shared_ptr_pointer<nullptr_t, _Dp, _AllocT> _CntrlBlk;
#ifndef _LIBCPP_CXX03_LANG
__cntrl_ = new _CntrlBlk(__p, _VSTD::move(__d), _AllocT());
#else
@ -665,8 +665,8 @@ public:
#endif
{
typedef typename __shared_ptr_default_allocator<_Yp>::type _AllocT;
typedef __shared_ptr_pointer<typename unique_ptr<_Yp, _Dp>::pointer, _Dp, _AllocT > _CntrlBlk;
__cntrl_ = new _CntrlBlk(__r.get(), __r.get_deleter(), _AllocT());
typedef __shared_ptr_pointer<typename unique_ptr<_Yp, _Dp>::pointer, _Dp, _AllocT> _CntrlBlk;
__cntrl_ = new _CntrlBlk(__r.get(), std::move(__r.get_deleter()), _AllocT());
__enable_weak_this(__r.get(), __r.get());
}
__r.release();
@ -689,7 +689,7 @@ public:
typedef typename __shared_ptr_default_allocator<_Yp>::type _AllocT;
typedef __shared_ptr_pointer<typename unique_ptr<_Yp, _Dp>::pointer,
reference_wrapper<typename remove_reference<_Dp>::type>,
_AllocT > _CntrlBlk;
_AllocT> _CntrlBlk;
__cntrl_ = new _CntrlBlk(__r.get(), _VSTD::ref(__r.get_deleter()), _AllocT());
__enable_weak_this(__r.get(), __r.get());
}

View File

@ -82,6 +82,13 @@ struct StatefulArrayDeleter {
}
};
struct MovingDeleter {
explicit MovingDeleter(int *moves) : moves_(moves) {}
MovingDeleter(MovingDeleter&& rhs) : moves_(rhs.moves_) { *moves_ += 1; }
void operator()(int*) const {}
int *moves_;
};
int main(int, char**)
{
{
@ -230,10 +237,39 @@ int main(int, char**)
assert(A::count == 0);
{
std::unique_ptr<int[]> ptr(new int[8]);
std::shared_ptr<int[]> p(std::move(ptr));
int *p = new int[8];
std::unique_ptr<int[]> u(p);
std::shared_ptr<int[]> s(std::move(u));
assert(u == nullptr);
assert(s.get() == p);
}
#endif // TEST_STD_VER > 14
{ // LWG 3548
{
int moves = 0;
int i = 42;
std::unique_ptr<int, MovingDeleter> u(&i, MovingDeleter(&moves));
assert(moves == 1);
std::shared_ptr<int> s(std::move(u));
assert(moves >= 2);
assert(u == nullptr);
assert(s.get() == &i);
}
#if TEST_STD_VER > 14
{
int moves = 0;
int a[8];
std::unique_ptr<int[], MovingDeleter> u(a, MovingDeleter(&moves));
assert(moves == 1);
std::shared_ptr<int[]> s = std::move(u);
assert(moves >= 2);
assert(u == nullptr);
assert(s.get() == a);
}
#endif // TEST_STD_VER > 14
}
#endif // TEST_STD_VER >= 14
return 0;
}