From patchwork Thu Oct 20 14:41:45 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jonathan Wakely X-Patchwork-Id: 78520 Delivered-To: patch@linaro.org Received: by 10.140.97.247 with SMTP id m110csp819322qge; Thu, 20 Oct 2016 07:42:24 -0700 (PDT) X-Received: by 10.98.80.2 with SMTP id e2mr1860704pfb.183.1476974544165; Thu, 20 Oct 2016 07:42:24 -0700 (PDT) Return-Path: Received: from sourceware.org (server1.sourceware.org. [209.132.180.131]) by mx.google.com with ESMTPS id sk10si22083073pac.345.2016.10.20.07.42.23 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 20 Oct 2016 07:42:24 -0700 (PDT) Received-SPF: pass (google.com: domain of gcc-patches-return-439136-patch=linaro.org@gcc.gnu.org designates 209.132.180.131 as permitted sender) client-ip=209.132.180.131; Authentication-Results: mx.google.com; dkim=pass header.i=@gcc.gnu.org; spf=pass (google.com: domain of gcc-patches-return-439136-patch=linaro.org@gcc.gnu.org designates 209.132.180.131 as permitted sender) smtp.mailfrom=gcc-patches-return-439136-patch=linaro.org@gcc.gnu.org DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:subject:message-id:references:mime-version:content-type :content-transfer-encoding:in-reply-to; q=dns; s=default; b=chRE izPGFY/CahHXFCx1ChzkTLc6IG8cGEGIVs6K7w+1aTetj9RDV+QYUbm1sK0wEK5Z Ehuo70L2UKrRcpVALhoshlVzSusDQMGKWHL/ZUjm+PY1CcsR1THTMjTlwtN2b9Mb LvTlgIA3WGmAsg3FZroInvGdIxCF2HBjdHHoJn0= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:subject:message-id:references:mime-version:content-type :content-transfer-encoding:in-reply-to; s=default; bh=NKwkM9PPlF X9l50bZsNQ2xzpLLQ=; b=lrp4QOF9r8ZdhtmdH6x2aG6gMedxvkdbTySxH2HGyd kUqYBEse5JYm3ZmQ05/hQyGiUFTmHaergqvTQNxxSiM2VxhUVKxdgaqAxHrgOUM7 lIVLXrhOg8/R+60dN39sIhNcPnfemKwdUUvf5YfXslVvZ7WD7KAVvaGF5xZCLpzc E= Received: (qmail 9817 invoked by alias); 20 Oct 2016 14:41:59 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 9794 invoked by uid 89); 20 Oct 2016 14:41:58 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=0.7 required=5.0 tests=BAYES_40, KAM_LAZY_DOMAIN_SECURITY, RP_MATCHES_RCVD, SPF_HELO_PASS autolearn=no version=3.3.2 spammy=1192, 7, 11927, Fundamentals, _tp_ptr X-Spam-User: qpsmtpd, 2 recipients X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Thu, 20 Oct 2016 14:41:48 +0000 Received: from int-mx09.intmail.prod.int.phx2.redhat.com (int-mx09.intmail.prod.int.phx2.redhat.com [10.5.11.22]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 395153F1E4; Thu, 20 Oct 2016 14:41:47 +0000 (UTC) Received: from localhost (ovpn-116-70.ams2.redhat.com [10.36.116.70]) by int-mx09.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id u9KEfkJw003866; Thu, 20 Oct 2016 10:41:46 -0400 Date: Thu, 20 Oct 2016 15:41:45 +0100 From: Jonathan Wakely To: libstdc++@gcc.gnu.org, gcc-patches@gcc.gnu.org Subject: Re: [PATCH] Prepare shared_ptr for array support Message-ID: <20161020144145.GJ2922@redhat.com> References: <20161020120838.GH2922@redhat.com> MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: <20161020120838.GH2922@redhat.com> X-Clacks-Overhead: GNU Terry Pratchett User-Agent: Mutt/1.7.0 (2016-08-17) On 20/10/16 13:08 +0100, Jonathan Wakely wrote: >This patch doesn't change very much, except for adding >std::reinterpret_pointer_cast, but it makes it very easy to add array >support to shared_ptr, as defined for the Library Fundamentals TS by >https://wg21.link/n3920 and in the process of being added to C++17 by >https://wg21.link/p0414r1 > >The main change is to consistently constrain all template constructors >and assignment operators. In std::shared_ptr we just forward the >checks to the std::__shared_ptr base class, so all the hard work is >done there. The base uses traits that can easily be extended to handle >array types without touching the uses of those traits (I have that >patch ready). Here's the patch to add array support, which is as simple as: - adding new __shared_count ctor that will result in delete[]; - adjusting the two __sp_xxx traits to handle the array cases; - moving operator* and operator-> into a new base class, and then specializing it so shared_ptr has operator[] instead; - changing element_type to be remove_extent::type instead of T; - disabling the __has_esft_base detection for array types. That allows us to remove 650 lines from the experimental::shared_ptr definition and just inherit directly from __shared_ptr. Note that the *only* change needed to std::shared_ptr or std::weak_ptr is to add an extension constructor (see below). My changes to trunk earlier today mean they are ready to suport arrays now. The code changes are all to the __shared_ptr and __weak_ptr base classes. Officially this isn't in the C++17 draft yet, but LWG already approved P0414R1 and it will be in the straw polls at the end of the Issaquah meeting next month. I'm not committing it to trunk yet, but I probably will do before the meeting, as I don't anticipate C++17 being published without this feature. The bigger question is whether we want to enable array support unconditionally, or only for C++17. In C++14 today shared_ptr and shared_ptr are valid ... although they're weird and not very usable. My preference (as shown in the patch) is to enable it unconditionally, but add some non-standard member functions for pre-C++17 to help transition. Specifically operator* and operator-> are defined for shared_ptr pre-C++17, and you can do this pre-C++17: shared_ptr p( unique_ptr(new int[1]) ); p.get()[0] = 1; assert( *p == 1 ); This is valid today, and we even have a test checking it works. The default_delete is copied into the shared_ptr and does delete[] when the refcount drops to zero. C++17 says this is ill-formed. This patch adds a non-standard constructor that allows this conversion, and the dereference, for C++11 and C++14 only. For C++17 the code needs to be changed to: shared_ptr p( unique_ptr(new int[1]) ); p.get()[0] = 1; assert( p[0] == 1 ); diff --git a/libstdc++-v3/doc/xml/manual/status_cxx2017.xml b/libstdc++-v3/doc/xml/manual/status_cxx2017.xml index a1190bc..6d10ac4 100644 --- a/libstdc++-v3/doc/xml/manual/status_cxx2017.xml +++ b/libstdc++-v3/doc/xml/manual/status_cxx2017.xml @@ -159,14 +159,13 @@ Feature-testing recommendations for C++. - Library Fundamentals V1 TS Components: shared_ptr<T[]> P0220R1 - No + 7 __cpp_lib_shared_ptr_arrays >= 201603 diff --git a/libstdc++-v3/include/bits/shared_ptr.h b/libstdc++-v3/include/bits/shared_ptr.h index 9f7a40c..fc4578a 100644 --- a/libstdc++-v3/include/bits/shared_ptr.h +++ b/libstdc++-v3/include/bits/shared_ptr.h @@ -277,6 +277,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION shared_ptr(unique_ptr<_Yp, _Del>&& __r) : __shared_ptr<_Tp>(std::move(__r)) { } +#if __cplusplus <= 201402L && _GLIBCXX_USE_DEPRECATED + // This non-standard constructor exists to support conversions that + // were possible in C++11 and C++14 but are ill-formed in C++17. + // If an exception is thrown this constructor has no effect. + template, __sp_array_delete>* = 0> + shared_ptr(unique_ptr<_Yp, _Del>&& __r) + : __shared_ptr<_Tp>(std::move(__r), __sp_array_delete()) { } +#endif + /** * @brief Construct an empty %shared_ptr. * @post use_count() == 0 && get() == nullptr diff --git a/libstdc++-v3/include/bits/shared_ptr_base.h b/libstdc++-v3/include/bits/shared_ptr_base.h index c74c92a..fc36676 100644 --- a/libstdc++-v3/include/bits/shared_ptr_base.h +++ b/libstdc++-v3/include/bits/shared_ptr_base.h @@ -558,6 +558,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _Impl _M_impl; }; + // The default deleter for shared_ptr and shared_ptr. + struct __sp_array_delete + { + template + void operator()(_Yp* __p) const { delete[] __p; } + }; template<_Lock_policy _Lp> class __shared_count @@ -581,6 +587,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } } + template + __shared_count(_Ptr __p, /* is_array = */ false_type) + : __shared_count(__p) + { } + + template + __shared_count(_Ptr __p, /* is_array = */ true_type) + : __shared_count(__p, __sp_array_delete{}, allocator()) + { } + template __shared_count(_Ptr __p, _Deleter __d) : __shared_count(__p, std::move(__d), allocator()) @@ -847,8 +863,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _M_pi = nullptr; } - // Helper traits for shared_ptr +#define __cpp_lib_shared_ptr_arrays 201603 + + // Helper traits for shared_ptr of array: + // A pointer type Y* is said to be compatible with a pointer type T* when + // either Y* is convertible to T* or Y is U[N] and T is U cv []. template struct __sp_compatible_with : false_type @@ -859,17 +879,161 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION : is_convertible<_Yp*, _Tp*>::type { }; + template + struct __sp_compatible_with<_Up(*)[_Nm], _Up(*)[]> + : true_type + { }; + + template + struct __sp_compatible_with<_Up(*)[_Nm], const _Up(*)[]> + : true_type + { }; + + template + struct __sp_compatible_with<_Up(*)[_Nm], volatile _Up(*)[]> + : true_type + { }; + + template + struct __sp_compatible_with<_Up(*)[_Nm], const volatile _Up(*)[]> + : true_type + { }; + + // Test conversion from Y(*)[N] to U(*)[N] without forming invalid type Y[N]. + template + struct __sp_is_constructible_arrN + : false_type + { }; + + template + struct __sp_is_constructible_arrN<_Up, _Nm, _Yp, __void_t<_Yp[_Nm]>> + : is_convertible<_Yp(*)[_Nm], _Up(*)[_Nm]>::type + { }; + + // Test conversion from Y(*)[] to U(*)[] without forming invalid type Y[]. + template + struct __sp_is_constructible_arr + : false_type + { }; + + template + struct __sp_is_constructible_arr<_Up, _Yp, __void_t<_Yp[]>> + : is_convertible<_Yp(*)[], _Up(*)[]>::type + { }; + + // Trait to check if shared_ptr can be constructed from Y*. + template + struct __sp_is_constructible; + + // When T is U[N], Y(*)[N] shall be convertible to T*; + template + struct __sp_is_constructible<_Up[_Nm], _Yp> + : __sp_is_constructible_arrN<_Up, _Nm, _Yp>::type + { }; + + // when T is U[], Y(*)[] shall be convertible to T*; + template + struct __sp_is_constructible<_Up[], _Yp> + : __sp_is_constructible_arr<_Up, _Yp>::type + { }; + + // otherwise, Y* shall be convertible to T*. + template + struct __sp_is_constructible + : is_convertible<_Yp*, _Tp*>::type + { }; + + + // Define operator* and operator-> for shared_ptr. + template::value, bool = is_void<_Tp>::value> + class __shared_ptr_access + { + public: + using element_type = _Tp; + + element_type& + operator*() const noexcept + { + __glibcxx_assert(_M_get() != nullptr); + return *_M_get(); + } + + element_type* + operator->() const noexcept + { + _GLIBCXX_DEBUG_PEDASSERT(_M_get() != nullptr); + return _M_get(); + } + + private: + element_type* + _M_get() const noexcept + { return static_cast*>(this)->get(); } + }; + + // Define operator-> for shared_ptr. template - class __shared_ptr + class __shared_ptr_access<_Tp, _Lp, false, true> { public: using element_type = _Tp; + element_type* + operator->() const noexcept + { + _GLIBCXX_DEBUG_PEDASSERT(_M_get() != nullptr); + return static_cast*>(this)->get(); + } + }; + + // Define operator[] for shared_ptr and shared_ptr. + template + class __shared_ptr_access<_Tp, _Lp, true, false> + { + public: + using element_type = typename remove_extent<_Tp>::type; + +#if __cplusplus <= 201402L + [[__deprecated__("shared_ptr::operator* is absent from C++17")]] + element_type& + operator*() const noexcept + { + __glibcxx_assert(_M_ptr != nullptr); + return *_M_get(); + } + + [[__deprecated__("shared_ptr::operator-> is absent from C++17")]] + element_type* + operator->() const noexcept + { + _GLIBCXX_DEBUG_PEDASSERT(_M_get() != nullptr); + return _M_get(); + } +#endif + + element_type& + operator[](ptrdiff_t __i) const + { + __glibcxx_assert(_M_get() != nullptr); + __glibcxx_assert(!extent<_Tp>::value || __i < extent<_Tp>::value); + return _M_get()[__i]; + } + private: - // Trait to check if shared_ptr can be constructed from Y*. - template - using __sp_is_constructible = is_convertible<_Yp*, _Tp1*>; + element_type* + _M_get() const noexcept + { return static_cast*>(this)->get(); } + }; + template + class __shared_ptr + : public __shared_ptr_access<_Tp, _Lp> + { + public: + using element_type = typename remove_extent<_Tp>::type; + + private: // Constraint for taking ownership of a pointer of type _Yp*: template using _SafeConv @@ -887,9 +1051,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // Constraint for construction from unique_ptr: template::pointer> - using _UniqCompatible = typename enable_if< - is_convertible<_Ptr, element_type*>::value - , _Res>::type; + using _UniqCompatible = typename enable_if<__and_< + __sp_compatible_with<_Yp*, _Tp*>, is_convertible<_Ptr, element_type*> + >::value, _Res>::type; // Constraint for assignment from unique_ptr: template @@ -908,7 +1072,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template> explicit __shared_ptr(_Yp* __p) - : _M_ptr(__p), _M_refcount(__p) + : _M_ptr(__p), _M_refcount(__p, typename is_array<_Tp>::type()) { static_assert( !is_void<_Yp>::value, "incomplete type" ); static_assert( sizeof(_Yp) > 0, "incomplete type" ); @@ -994,6 +1158,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _M_enable_shared_from_this_with(__raw); } +#if __cplusplus <= 201402L && _GLIBCXX_USE_DEPRECATED + protected: + // If an exception is thrown this constructor has no effect. + template>, is_array<_Tp1>, + is_convertible::pointer, _Tp*> + >::value, bool>::type = true> + __shared_ptr(unique_ptr<_Tp1, _Del>&& __r, __sp_array_delete) + : _M_ptr(__r.get()), _M_refcount() + { + auto __raw = _S_raw_ptr(__r.get()); + _M_refcount = __shared_count<_Lp>(std::move(__r)); + _M_enable_shared_from_this_with(__raw); + } + public: +#endif + #if _GLIBCXX_USE_DEPRECATED // Postcondition: use_count() == 1 and __r.get() == 0 template> @@ -1067,21 +1249,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION reset(_Yp* __p, _Deleter __d, _Alloc __a) { __shared_ptr(__p, __d, std::move(__a)).swap(*this); } - // Allow class instantiation when _Tp is [cv-qual] void. - typename std::add_lvalue_reference::type - operator*() const noexcept - { - __glibcxx_assert(_M_ptr != 0); - return *_M_ptr; - } - - element_type* - operator->() const noexcept - { - _GLIBCXX_DEBUG_PEDASSERT(_M_ptr != 0); - return _M_ptr; - } - element_type* get() const noexcept { return _M_ptr; } @@ -1192,7 +1359,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template struct __has_esft_base<_Yp, __void_t<__esft_base_t<_Yp>>> - : true_type { }; + : __not_> { }; // No enable shared_from_this for arrays template typename enable_if<__has_esft_base<_Yp>::value>::type @@ -1427,7 +1594,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION using _Assignable = _Compatible<_Yp, __weak_ptr&>; public: - using element_type = _Tp; + using element_type = typename remove_extent<_Tp>::type; constexpr __weak_ptr() noexcept : _M_ptr(nullptr), _M_refcount() diff --git a/libstdc++-v3/include/experimental/bits/shared_ptr.h b/libstdc++-v3/include/experimental/bits/shared_ptr.h index e8c533e..8a1fc52 100644 --- a/libstdc++-v3/include/experimental/bits/shared_ptr.h +++ b/libstdc++-v3/include/experimental/bits/shared_ptr.h @@ -46,665 +46,20 @@ namespace experimental inline namespace fundamentals_v2 { _GLIBCXX_BEGIN_NAMESPACE_VERSION - template class enable_shared_from_this; -_GLIBCXX_END_NAMESPACE_VERSION -} // namespace fundamentals_v2 -} // namespace experimental - -#define __cpp_lib_experimental_shared_ptr_arrays 201406 - -_GLIBCXX_BEGIN_NAMESPACE_VERSION - - /* - * The specification of std::experimental::shared_ptr is slightly different - * to std::shared_ptr (specifically in terms of "compatible" pointers) so - * to implement std::experimental::shared_ptr without too much duplication - * we make it derive from a partial specialization of std::__shared_ptr - * using a special tag type, __libfund_v1. - * - * There are two partial specializations for the tag type, supporting the - * different interfaces of the array and non-array forms. - */ - - template ::value> - struct __libfund_v1 { using type = _Tp; }; - - // Partial specialization for base class of experimental::shared_ptr - // (i.e. the non-array form of experimental::shared_ptr) - template - class __shared_ptr<__libfund_v1<_Tp, false>, _Lp> - : private __shared_ptr<_Tp, _Lp> - { - // For non-arrays, Y* is compatible with T* if Y* is convertible to T*. - template - using _Compatible - = enable_if_t, _Res>; - - template::pointer, - typename _Res = void> - using _UniqCompatible = enable_if_t< - experimental::is_convertible_v<_Yp*, _Tp*> - && experimental::is_convertible_v<_Ptr, _Tp*>, - _Res>; - - using _Base_type = __shared_ptr<_Tp>; - - _Base_type& _M_get_base() { return *this; } - const _Base_type& _M_get_base() const { return *this; } - - public: - using element_type = _Tp; - - constexpr __shared_ptr() noexcept = default; - - template> - explicit - __shared_ptr(_Tp1* __p) - : _Base_type(__p) - { } - - template> - __shared_ptr(_Tp1* __p, _Deleter __d) - : _Base_type(__p, __d) - { } - - template> - __shared_ptr(_Tp1* __p, _Deleter __d, _Alloc __a) - : _Base_type(__p, __d, __a) - { } - - template - __shared_ptr(nullptr_t __p, _Deleter __d) - : _Base_type(__p, __d) - { } - - template - __shared_ptr(nullptr_t __p, _Deleter __d, _Alloc __a) - : _Base_type(__p, __d, __a) - { } - - template - __shared_ptr(const __shared_ptr<__libfund_v1<_Tp1>, _Lp>& __r, - element_type* __p) noexcept - : _Base_type(__r._M_get_base(), __p) - { } - - __shared_ptr(const __shared_ptr&) noexcept = default; - __shared_ptr(__shared_ptr&&) noexcept = default; - __shared_ptr& operator=(const __shared_ptr&) noexcept = default; - __shared_ptr& operator=(__shared_ptr&&) noexcept = default; - ~__shared_ptr() = default; - - template> - __shared_ptr(const __shared_ptr<__libfund_v1<_Tp1>, _Lp>& __r) noexcept - : _Base_type(__r._M_get_base()) - { } - - template> - __shared_ptr(__shared_ptr<__libfund_v1<_Tp1>, _Lp>&& __r) noexcept - : _Base_type(std::move((__r._M_get_base()))) - { } - - template> - explicit - __shared_ptr(const __weak_ptr<__libfund_v1<_Tp1>, _Lp>& __r) - : _Base_type(__r._M_get_base()) - { } - - template> - __shared_ptr(unique_ptr<_Tp1, _Del>&& __r) - : _Base_type(std::move(__r)) - { } - -#if _GLIBCXX_USE_DEPRECATED - // Postcondition: use_count() == 1 and __r.get() == 0 - template> - __shared_ptr(std::auto_ptr<_Tp1>&& __r) - : _Base_type(std::move(__r)) - { } -#endif - - constexpr __shared_ptr(nullptr_t) noexcept : __shared_ptr() { } - - // reset - void - reset() noexcept - { __shared_ptr(nullptr).swap(*this); } - - template - _Compatible<_Tp1> - reset(_Tp1* __p) - { - _GLIBCXX_DEBUG_ASSERT(__p == 0 || __p != get()); - __shared_ptr(__p).swap(*this); - } - - template - _Compatible<_Tp1> - reset(_Tp1* __p, _Deleter __d) - { __shared_ptr(__p, __d).swap(*this); } - - template - _Compatible<_Tp1> - reset(_Tp1* __p, _Deleter __d, _Alloc __a) - { __shared_ptr(__p, __d, std::move(__a)).swap(*this); } - - using _Base_type::operator*; - using _Base_type::operator->; - - template - _Compatible<_Tp1, __shared_ptr&> - operator=(const __shared_ptr<__libfund_v1<_Tp1>, _Lp>& __r) noexcept - { - _Base_type::operator=(__r._M_get_base()); - return *this; - } - - template - _Compatible<_Tp1, __shared_ptr&> - operator=(__shared_ptr<__libfund_v1<_Tp1>, _Lp>&& __r) noexcept - { - _Base_type::operator=(std::move(__r._M_get_base())); - return *this; - } - - template - _UniqCompatible<_Tp1, _Del, __shared_ptr&> - operator=(unique_ptr<_Tp1, _Del>&& __r) - { - _Base_type::operator=(std::move(__r)); - return *this; - } - -#if _GLIBCXX_USE_DEPRECATED - template - _Compatible<_Tp1, __shared_ptr&> - operator=(std::auto_ptr<_Tp1>&& __r) - { - _Base_type::operator=(std::move(__r)); - return *this; - } -#endif - - void - swap(__shared_ptr& __other) noexcept - { _Base_type::swap(__other); } - - template - bool - owner_before(__shared_ptr<__libfund_v1<_Tp1>, _Lp> const& __rhs) const - { return _Base_type::owner_before(__rhs._M_get_base()); } - - template - bool - owner_before(__weak_ptr<__libfund_v1<_Tp1>, _Lp> const& __rhs) const - { return _Base_type::owner_before(__rhs._M_get_base()); } - - using _Base_type::operator bool; - using _Base_type::get; - using _Base_type::unique; - using _Base_type::use_count; - - protected: - - // make_shared not yet support for shared_ptr_arrays - //template - // __shared_ptr(_Sp_make_shared_tag __tag, const _Alloc& __a, - // _Args&&... __args) - // : _M_ptr(), _M_refcount(__tag, (_Tp*)0, __a, - // std::forward<_Args>(__args)...) - // { - // void* __p = _M_refcount._M_get_deleter(typeid(__tag)); - // _M_ptr = static_cast<_Tp*>(__p); - // } - - // __weak_ptr::lock() - __shared_ptr(const __weak_ptr<__libfund_v1<_Tp>, _Lp>& __r, - std::nothrow_t) - : _Base_type(__r._M_get_base(), std::nothrow) - { } - - private: - template friend class __weak_ptr; - template friend class __shared_ptr; - - // TODO - template - friend _Del* get_deleter(const __shared_ptr<_Tp1, _Lp1>&) noexcept; - }; - - // Helper traits for shared_ptr of array: - // Trait that tests if Y* is compatible with T*, for shared_ptr purposes. - template - struct __sp_compatible - : is_convertible<_Yp*, _Tp*>::type - { }; + // 8.2.1 - template - struct __sp_compatible<_Tp[_Nm], _Tp[]> - : true_type - { }; - - template - struct __sp_compatible<_Tp[_Nm], const _Tp[]> - : true_type - { }; + template class shared_ptr; + template class weak_ptr; + template class enable_shared_from_this; template constexpr bool __sp_compatible_v - = __sp_compatible<_Yp, _Tp>::value; - - // Test conversion from Y(*)[N] to U(*)[N] without forming invalid type Y[N]. - template - struct __sp_is_constructible_arrN - : false_type - { }; - - template - struct __sp_is_constructible_arrN<_Up, _Nm, _Yp, __void_t<_Yp[_Nm]>> - : is_convertible<_Yp(*)[_Nm], _Up(*)[_Nm]>::type - { }; - - // Test conversion from Y(*)[] to U(*)[] without forming invalid type Y[]. - template - struct __sp_is_constructible_arr - : false_type - { }; - - template - struct __sp_is_constructible_arr<_Up, _Yp, __void_t<_Yp[]>> - : is_convertible<_Yp(*)[], _Up(*)[]>::type - { }; - - // Trait to check if shared_ptr can be constructed from Y*. - template - struct __sp_is_constructible; - - // When T is U[N], Y(*)[N] shall be convertible to T*; - template - struct __sp_is_constructible<_Up[_Nm], _Yp> - : __sp_is_constructible_arrN<_Up, _Nm, _Yp>::type - { }; - - // when T is U[], Y(*)[] shall be convertible to T*; - template - struct __sp_is_constructible<_Up[], _Yp> - : __sp_is_constructible_arr<_Up, _Yp>::type - { }; - - // otherwise, Y* shall be convertible to T*. - template - struct __sp_is_constructible - : is_convertible<_Yp*, _Tp*>::type - { }; + = std::__sp_compatible_with<_Yp*, _Tp*>::value; template constexpr bool __sp_is_constructible_v - = __sp_is_constructible<_Tp, _Yp>::value; - - - // Partial specialization for base class of experimental::shared_ptr - // and experimental::shared_ptr (i.e. the array forms). - template - class __shared_ptr<__libfund_v1<_Tp, true>, _Lp> - : private __shared_ptr, _Lp> - { - public: - using element_type = remove_extent_t<_Tp>; - - private: - struct _Array_deleter - { - void - operator()(element_type const *__p) const - { delete [] __p; } - }; - - // Constraint for constructing/resetting with a pointer of type _Yp*: - template - using _SafeConv = enable_if_t<__sp_is_constructible_v<_Tp, _Yp>>; - - // Constraint for constructing/assigning from smart_pointer<_Tp1>: - template - using _Compatible = enable_if_t<__sp_compatible_v<_Tp1, _Tp>, _Res>; - - // Constraint for constructing/assigning from unique_ptr<_Tp1, _Del>: - template::pointer, - typename _Res = void> - using _UniqCompatible = enable_if_t< - __sp_compatible_v<_Tp1, _Tp> - && experimental::is_convertible_v<_Ptr, element_type*>, - _Res>; - - using _Base_type = __shared_ptr; - - _Base_type& _M_get_base() { return *this; } - const _Base_type& _M_get_base() const { return *this; } - - public: - constexpr __shared_ptr() noexcept - : _Base_type() - { } - - template> - explicit - __shared_ptr(_Tp1* __p) - : _Base_type(__p, _Array_deleter()) - { } - - template> - __shared_ptr(_Tp1* __p, _Deleter __d) - : _Base_type(__p, __d) - { } - - template> - __shared_ptr(_Tp1* __p, _Deleter __d, _Alloc __a) - : _Base_type(__p, __d, __a) - { } - - template - __shared_ptr(nullptr_t __p, _Deleter __d) - : _Base_type(__p, __d) - { } - - template - __shared_ptr(nullptr_t __p, _Deleter __d, _Alloc __a) - : _Base_type(__p, __d, __a) - { } - - template - __shared_ptr(const __shared_ptr<__libfund_v1<_Tp1>, _Lp>& __r, - element_type* __p) noexcept - : _Base_type(__r._M_get_base(), __p) - { } - - __shared_ptr(const __shared_ptr&) noexcept = default; - __shared_ptr(__shared_ptr&&) noexcept = default; - __shared_ptr& operator=(const __shared_ptr&) noexcept = default; - __shared_ptr& operator=(__shared_ptr&&) noexcept = default; - ~__shared_ptr() = default; - - template> - __shared_ptr(const __shared_ptr<__libfund_v1<_Tp1>, _Lp>& __r) noexcept - : _Base_type(__r._M_get_base()) - { } - - template> - __shared_ptr(__shared_ptr<__libfund_v1<_Tp1>, _Lp>&& __r) noexcept - : _Base_type(std::move((__r._M_get_base()))) - { } - - template> - explicit - __shared_ptr(const __weak_ptr<__libfund_v1<_Tp1>, _Lp>& __r) - : _Base_type(__r._M_get_base()) - { } - - template> - __shared_ptr(unique_ptr<_Tp1, _Del>&& __r) - : _Base_type(std::move(__r)) - { } - -#if _GLIBCXX_USE_DEPRECATED - // Postcondition: use_count() == 1 and __r.get() == 0 - template> - __shared_ptr(auto_ptr<_Tp1>&& __r) - : _Base_type(std::move(__r)) - { } -#endif - - constexpr __shared_ptr(nullptr_t) noexcept : __shared_ptr() { } - - // reset - void - reset() noexcept - { __shared_ptr(nullptr).swap(*this); } - - template - _SafeConv<_Tp1> - reset(_Tp1* __p) - { - _GLIBCXX_DEBUG_ASSERT(__p == 0 || __p != get()); - __shared_ptr(__p, _Array_deleter()).swap(*this); - } - - template - _SafeConv<_Tp1> - reset(_Tp1* __p, _Deleter __d) - { __shared_ptr(__p, __d).swap(*this); } - - template - _SafeConv<_Tp1> - reset(_Tp1* __p, _Deleter __d, _Alloc __a) - { __shared_ptr(__p, __d, std::move(__a)).swap(*this); } - - element_type& - operator[](ptrdiff_t i) const noexcept - { - _GLIBCXX_DEBUG_ASSERT(get() != 0 && i >= 0); - return get()[i]; - } - - template - _Compatible<_Tp1, __shared_ptr&> - operator=(const __shared_ptr<__libfund_v1<_Tp1>, _Lp>& __r) noexcept - { - _Base_type::operator=(__r._M_get_base()); - return *this; - } - - template - _Compatible<_Tp1, __shared_ptr&> - operator=(__shared_ptr<__libfund_v1<_Tp1>, _Lp>&& __r) noexcept - { - _Base_type::operator=(std::move(__r._M_get_base())); - return *this; - } - - template - _UniqCompatible<_Tp1, _Del, __shared_ptr&> - operator=(unique_ptr<_Tp1, _Del>&& __r) - { - _Base_type::operator=(std::move(__r)); - return *this; - } - -#if _GLIBCXX_USE_DEPRECATED - template - _Compatible<_Tp1, __shared_ptr&> - operator=(auto_ptr<_Tp1>&& __r) - { - _Base_type::operator=(std::move(__r)); - return *this; - } -#endif - - void - swap(__shared_ptr& __other) noexcept - { _Base_type::swap(__other); } - - template - bool - owner_before(__shared_ptr<__libfund_v1<_Tp1>, _Lp> const& __rhs) const - { return _Base_type::owner_before(__rhs._M_get_base()); } - - template - bool - owner_before(__weak_ptr<__libfund_v1<_Tp1>, _Lp> const& __rhs) const - { return _Base_type::owner_before(__rhs._M_get_base()); } - - using _Base_type::operator bool; - using _Base_type::get; - using _Base_type::unique; - using _Base_type::use_count; - - protected: - - // make_shared not yet support for shared_ptr_arrays - //template - // __shared_ptr(_Sp_make_shared_tag __tag, const _Alloc& __a, - // _Args&&... __args) - // : _M_ptr(), _M_refcount(__tag, (_Tp*)0, __a, - // std::forward<_Args>(__args)...) - // { - // void* __p = _M_refcount._M_get_deleter(typeid(__tag)); - // _M_ptr = static_cast<_Tp*>(__p); - // } - - // __weak_ptr::lock() - __shared_ptr(const __weak_ptr<__libfund_v1<_Tp>, _Lp>& __r, - std::nothrow_t) - : _Base_type(__r._M_get_base(), std::nothrow) - { } - - private: - template friend class __weak_ptr; - template friend class __shared_ptr; - - // TODO - template - friend _Del* get_deleter(const __shared_ptr<_Tp1, _Lp1>&) noexcept; - }; - - // weak_ptr specialization for __shared_ptr array - template - class __weak_ptr<__libfund_v1<_Tp>, _Lp> - : __weak_ptr, _Lp> - { - template - using _Compatible - = enable_if_t<__sp_compatible_v<_Tp1, _Tp>, _Res>; - - using _Base_type = __weak_ptr>; - - _Base_type& _M_get_base() { return *this; } - const _Base_type& _M_get_base() const { return *this; } - - public: - using element_type = remove_extent_t<_Tp>; - - constexpr __weak_ptr() noexcept - : _Base_type() - { } - - __weak_ptr(const __weak_ptr&) noexcept = default; - - ~__weak_ptr() = default; - - template> - __weak_ptr(const __weak_ptr<__libfund_v1<_Tp1>, _Lp>& __r) noexcept - : _Base_type(__r._M_get_base()) - { } - - template> - __weak_ptr(const __shared_ptr<__libfund_v1<_Tp1>, _Lp>& __r) noexcept - : _Base_type(__r._M_get_base()) - { } - - __weak_ptr(__weak_ptr&& __r) noexcept - : _Base_type(std::move(__r)) - { } - - template> - __weak_ptr(__weak_ptr<__libfund_v1<_Tp1>, _Lp>&& __r) noexcept - : _Base_type(std::move(__r._M_get_base())) - { } - - __weak_ptr& - operator=(const __weak_ptr& __r) noexcept = default; - - template - _Compatible<_Tp1, __weak_ptr&> - operator=(const __weak_ptr<__libfund_v1<_Tp1>, _Lp>& __r) noexcept - { - this->_Base_type::operator=(__r._M_get_base()); - return *this; - } - - template - _Compatible<_Tp1, __weak_ptr&> - operator=(const __shared_ptr<_Tp1, _Lp>& __r) noexcept - { - this->_Base_type::operator=(__r._M_get_base()); - return *this; - } - - __weak_ptr& - operator=(__weak_ptr&& __r) noexcept - { - this->_Base_type::operator=(std::move(__r)); - return *this; - } - - template - _Compatible<_Tp1, __weak_ptr&> - operator=(__weak_ptr<_Tp1, _Lp>&& __r) noexcept - { - this->_Base_type::operator=(std::move(__r._M_get_base())); - return *this; - } - - void - swap(__weak_ptr& __other) noexcept - { this->_Base_type::swap(__other); } - - template - bool - owner_before(const __shared_ptr<__libfund_v1<_Tp1>, _Lp>& __rhs) const - { return _Base_type::owner_before(__rhs._M_get_base()); } - - template - bool - owner_before(const __weak_ptr<__libfund_v1<_Tp1>, _Lp>& __rhs) const - { return _Base_type::owner_before(__rhs._M_get_base()); } - - __shared_ptr<__libfund_v1<_Tp>, _Lp> - lock() const noexcept // should not be element_type - { return __shared_ptr<__libfund_v1<_Tp>, _Lp>(*this, std::nothrow); } - - using _Base_type::use_count; - using _Base_type::expired; - using _Base_type::reset; - - private: - // Used by __enable_shared_from_this. - void - _M_assign(element_type* __ptr, - const __shared_count<_Lp>& __refcount) noexcept - { this->_Base_type::_M_assign(__ptr, __refcount); } - - template friend class __shared_ptr; - template friend class __weak_ptr; - friend class __enable_shared_from_this<_Tp, _Lp>; - friend class experimental::enable_shared_from_this<_Tp>; - friend class enable_shared_from_this<_Tp>; - }; - -_GLIBCXX_END_NAMESPACE_VERSION - -namespace experimental -{ -inline namespace fundamentals_v2 -{ -_GLIBCXX_BEGIN_NAMESPACE_VERSION - - // 8.2.1 - - template class shared_ptr; - template class weak_ptr; - - template - using __shared_ptr = std::__shared_ptr<__libfund_v1<_Tp>, _Lp>; - - template - using __weak_ptr = std::__weak_ptr<__libfund_v1<_Tp>, _Lp>; + = std::__sp_is_constructible<_Tp, _Yp>::value; template class shared_ptr : public __shared_ptr<_Tp> @@ -1128,16 +483,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { __a.swap(__b); } /// C++14 ??20.8.2.2.10 - template + template inline _Del* - get_deleter(const __shared_ptr<_Tp, _Lp>& __p) noexcept + get_deleter(const shared_ptr<_Tp>& __p) noexcept { return std::get_deleter<_Del>(__p); } // C++14 ??20.8.2.2.11 - template + template inline std::basic_ostream<_Ch, _Tr>& - operator<<(std::basic_ostream<_Ch, _Tr>& __os, - const __shared_ptr<_Tp, _Lp>& __p) + operator<<(std::basic_ostream<_Ch, _Tr>& __os, const shared_ptr<_Tp>& __p) { __os << __p.get(); return __os; diff --git a/libstdc++-v3/testsuite/20_util/shared_ptr/cons/unique_ptr_array.cc b/libstdc++-v3/testsuite/20_util/shared_ptr/cons/unique_ptr_array.cc index 72eed47..bc1fcf1 100644 --- a/libstdc++-v3/testsuite/20_util/shared_ptr/cons/unique_ptr_array.cc +++ b/libstdc++-v3/testsuite/20_util/shared_ptr/cons/unique_ptr_array.cc @@ -22,6 +22,13 @@ #include #include +#if __cpp_lib_shared_ptr_arrays >= 201603 +# define SHARED_PTR_ARRAYS +#endif +#if __cpp_lib_enable_shared_from_this >= 201603 +# define WEAK_FROM_THIS +#endif + int destroyed = 0; struct A : std::enable_shared_from_this @@ -36,12 +43,22 @@ int test01() { std::unique_ptr up(new A[2]); +#ifdef SHARED_PTR_ARRAYS + std::shared_ptr sp(std::move(up)); +#else std::shared_ptr sp(std::move(up)); +#endif VERIFY( up.get() == 0 ); VERIFY( sp.get() != 0 ); VERIFY( sp.use_count() == 1 ); +#ifdef SHARED_PTR_ARRAYS +# ifdef WEAK_FROM_THIS + VERIFY( sp[0].weak_from_this().expired() ); +# endif +#else VERIFY( sp->shared_from_this() != nullptr ); +#endif sp.reset(); VERIFY( destroyed == 2 );