From patchwork Sun Nov 13 22:57:37 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jonathan Wakely X-Patchwork-Id: 81983 Delivered-To: patch@linaro.org Received: by 10.140.97.165 with SMTP id m34csp761623qge; Sun, 13 Nov 2016 14:58:22 -0800 (PST) X-Received: by 10.99.251.5 with SMTP id o5mr23586190pgh.160.1479077902147; Sun, 13 Nov 2016 14:58:22 -0800 (PST) Return-Path: Received: from sourceware.org (server1.sourceware.org. [209.132.180.131]) by mx.google.com with ESMTPS id m6si1484001pgg.171.2016.11.13.14.58.21 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Sun, 13 Nov 2016 14:58:22 -0800 (PST) Received-SPF: pass (google.com: domain of gcc-patches-return-441275-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-441275-patch=linaro.org@gcc.gnu.org designates 209.132.180.131 as permitted sender) smtp.mailfrom=gcc-patches-return-441275-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=ftDP lwkh41AVrQvlS5K5RkmoHDOW4X+seciZ/wwsQmI3MXoGH5ZWoPjQJTd/7s/4p8i5 XkWQaXs7jEIueoapADXmje57fqK5ITw7ni6tk8oTse5WwjIkKcEutiOhZ3c5bAVq kT/tC3fe3jiH+BzjcAkD6zdtpzaFzn7IBIbmO4U= 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=9DwodsBD+3 rSgiJmDwOEvS3I9Rg=; b=vnbRxfxdVhh23EQhsQZ+3NAFIh1p6nTh0/PfniwIe7 uTr741CWWqpkA9U6apj+lt53xxLLWtOExBN+yHnlYeXGY//vEX3oG88mvtia/Te7 KbSu1KseljujdGEbxRXFwlIDnuob0Tuftde9nPCcHcaOod8vbuhFe0dsz+3wpxEB Q= Received: (qmail 47820 invoked by alias); 13 Nov 2016 22:57:54 -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 47792 invoked by uid 89); 13 Nov 2016 22:57:52 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-3.3 required=5.0 tests=BAYES_05, RP_MATCHES_RCVD, SPF_HELO_PASS autolearn=ham version=3.3.2 spammy=specializing, 1999, anticipate, bgcolor 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; Sun, 13 Nov 2016 22:57:41 +0000 Received: from int-mx13.intmail.prod.int.phx2.redhat.com (int-mx13.intmail.prod.int.phx2.redhat.com [10.5.11.26]) (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 7ABB5C056800; Sun, 13 Nov 2016 22:57:40 +0000 (UTC) Received: from localhost (ovpn-116-20.ams2.redhat.com [10.36.116.20]) by int-mx13.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id uADMvcOb017447; Sun, 13 Nov 2016 17:57:38 -0500 Date: Sun, 13 Nov 2016 22:57:37 +0000 From: Jonathan Wakely To: libstdc++@gcc.gnu.org, gcc-patches@gcc.gnu.org Subject: Re: [PATCH] Prepare shared_ptr for array support Message-ID: <20161113225737.GL21992@redhat.com> References: <20161020120838.GH2922@redhat.com> <20161020144145.GJ2922@redhat.com> MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: <20161020144145.GJ2922@redhat.com> X-Clacks-Overhead: GNU Terry Pratchett User-Agent: Mutt/1.7.1 (2016-10-04) On 20/10/16 15:41 +0100, Jonathan Wakely wrote: >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 ); Here's what I'm committing, now that we've voted array support into the WP (again). Tested powerpc64le-linux, committed to trunk. commit fc1957b66af979b174d7120c9311479842a6aefb Author: Jonathan Wakely Date: Sun Nov 13 20:41:17 2016 +0000 Add array support to std::shared_ptr for C++17 * doc/xml/manual/status_cxx2017.xml: Update status. * doc/html/manual/status.html: Regenerate. * include/bits/shared_ptr.h (shared_ptr(unique_ptr<_Yp, _Del>)): Add extension constructor to maintain C++14 behaviour. * include/bits/shared_ptr_base.h (__sp_array_delete): Add new struct. (__shared_count(_Ptr, false_type), __shared_count(_Ptr, true_type)): New constructors. (__sp_compatible_with, __sp_is_constructible): Add specializations for array support. (__sp_is_constructible_arr, __sp_is_constructible_arrN): New helpers. (__shared_ptr_access): New base class for observer member functions. (__shared_ptr::element_type): Use remove_extent. (__shared_ptr::_UniqCompatible): Add __sp_compatible_with check. (__shared_ptr(_Yp*)): Use tag dispatching to call new __shared_count constructor. (__shared_ptr(unique_ptr<_Yp, _Del>)): Add extension constructor. (__shared_ptr::operator*, __shared_ptr::operator->): Remove and inherit from __shared_ptr_access base class. (__shared_ptr::__has_esft_base): Return false for array types. (__weak_ptr::element_type): Use remove_extent. * include/experimental/bits/shared_ptr.h (__libfund_v1): Remove. (__shared_ptr<__libfund_v1<_Tp>>): Remove specializations. (__wak_ptr<__libfund_v1<_Tp>>): Likewise. (experimental::__sp_compatible_v): Redefine using __sp_compatible_with. (experimental::__sp_is_constructible_v): Redefine using __sp_is_constructible. (get_deleter, operator<<): Change argument from __shared_ptr to shared_ptr. * testsuite/20_util/shared_ptr/cons/array.cc: New test. * testsuite/20_util/shared_ptr/cons/unique_ptr_array.cc: Adjust for new behaviour. * testsuite/20_util/shared_ptr/observers/array.cc: Test observers for arrays. * testsuite/20_util/shared_ptr/observers/array_neg.cc: New test. diff --git a/libstdc++-v3/doc/xml/manual/status_cxx2017.xml b/libstdc++-v3/doc/xml/manual/status_cxx2017.xml index d008bd9e..dbb26c8 100644 --- a/libstdc++-v3/doc/xml/manual/status_cxx2017.xml +++ b/libstdc++-v3/doc/xml/manual/status_cxx2017.xml @@ -158,14 +158,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 e562a42..cbe4144 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 5e344b8..953aa87 100644 --- a/libstdc++-v3/include/bits/shared_ptr_base.h +++ b/libstdc++-v3/include/bits/shared_ptr_base.h @@ -559,6 +559,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 @@ -582,6 +588,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()) @@ -848,8 +864,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 @@ -860,17 +880,161 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION : is_convertible<_Yp*, _Tp*>::type { }; - template - class __shared_ptr + 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; - private: - // Trait to check if shared_ptr can be constructed from Y*. - template - using __sp_is_constructible = is_convertible<_Yp*, _Tp1*>; + 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_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: + 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 @@ -888,9 +1052,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 @@ -909,7 +1073,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" ); @@ -995,6 +1159,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> @@ -1068,21 +1250,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; } @@ -1193,7 +1360,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 @@ -1428,7 +1595,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 - { }; - - template - struct __sp_compatible<_Tp[_Nm], _Tp[]> - : true_type - { }; - - template - struct __sp_compatible<_Tp[_Nm], const _Tp[]> - : true_type - { }; - - 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 - { }; - - 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 + // 8.2.1 template class shared_ptr; template class weak_ptr; + template class enable_shared_from_this; - template - using __shared_ptr = std::__shared_ptr<__libfund_v1<_Tp>, _Lp>; + template + constexpr bool __sp_compatible_v + = std::__sp_compatible_with<_Yp*, _Tp*>::value; - template - using __weak_ptr = std::__weak_ptr<__libfund_v1<_Tp>, _Lp>; + template + constexpr bool __sp_is_constructible_v + = 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/array.cc b/libstdc++-v3/testsuite/20_util/shared_ptr/cons/array.cc new file mode 100644 index 0000000..d56dc66 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/shared_ptr/cons/array.cc @@ -0,0 +1,273 @@ +// { dg-do run { target c++11 } } + +// Copyright (C) 2016 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 +// . + +#include +#include + +// C++1z 20.11.2.2.1 shared_ptr constructors [util.smartptr.shared.const] + +template +constexpr bool check() +{ + using std::shared_ptr; + using std::is_constructible; + return !is_constructible, shared_ptr>::value + && !is_constructible, shared_ptr&>::value; +} + +static_assert( check() ); +static_assert( check() ); +static_assert( check() ); +static_assert( check() ); +static_assert( check() ); +static_assert( check() ); +static_assert( check() ); + +int count = 0; + +struct A { + A() { ++count; } + ~A() { --count; } +}; + +struct B : A { }; + +static_assert( check() ); +static_assert( check() ); +static_assert( check() ); +static_assert( check() ); +static_assert( check() ); +static_assert( check() ); +static_assert( check() ); +static_assert( check() ); + +void +test01() +{ + std::shared_ptr p; + VERIFY( p.get() == nullptr ); + VERIFY( p.use_count() == 0 ); + p.reset(); + VERIFY( count == 0 ); +} + +void +test02() +{ + std::shared_ptr p; + VERIFY( p.get() == nullptr ); + VERIFY( p.use_count() == 0 ); + p.reset(); + VERIFY( count == 0 ); +} + +void +test03() +{ + std::shared_ptr p(nullptr); + VERIFY( p.get() == nullptr ); + VERIFY( p.use_count() == 0 ); + p.reset(); + VERIFY( count == 0 ); +} + +void +test04() +{ + std::shared_ptr p(nullptr); + VERIFY( p.get() == nullptr ); + VERIFY( p.use_count() == 0 ); + p.reset(); + VERIFY( count == 0 ); +} + +// Construction from pointer + +void +test05() +{ + A * const a = nullptr; + std::shared_ptr p(a); + VERIFY( p.get() == nullptr ); + VERIFY( p.use_count() == 1 ); + p.reset(); + VERIFY( count == 0 ); +} + +void +test06() +{ + A * const a = nullptr; + std::shared_ptr p(a); + VERIFY( p.get() == nullptr ); + VERIFY( p.use_count() == 1 ); + p.reset(); + VERIFY( count == 0 ); +} + +void +test07() +{ + A * const a = new A[2]; + std::shared_ptr p(a); + VERIFY( p.get() == a ); + VERIFY( p.use_count() == 1 ); + p.reset(); + VERIFY( count == 0 ); +} + +void +test08() +{ + A * const a = new A[2]; + std::shared_ptr p(a); + VERIFY( p.get() == a ); + VERIFY( p.use_count() == 1 ); + p.reset(); + VERIFY( count == 0 ); +} + +// Converting constrcutor + +void +test09() +{ + A * const a = new A[2]; + std::shared_ptr p(a); + std::shared_ptr p2(p); + VERIFY( p2.get() == a ); + VERIFY( p.use_count() == 2 ); + VERIFY( p2.use_count() == 2 ); + p.reset(); + VERIFY( count != 0 ); + p2.reset(); + VERIFY( count == 0 ); +} + +void +test10() +{ + A * const a = new A[2]; + std::shared_ptr p(a); + std::shared_ptr p2(p); + VERIFY( p2.get() == a ); + VERIFY( p.use_count() == 2 ); + VERIFY( p2.use_count() == 2 ); + p.reset(); + VERIFY( count != 0 ); + p2.reset(); + VERIFY( count == 0 ); +} + +void +test11() +{ + A * const a = new A[2]; + std::shared_ptr p(a); + std::shared_ptr p2(p); + VERIFY( p2.get() == a ); + VERIFY( p.use_count() == 2 ); + VERIFY( p2.use_count() == 2 ); + p.reset(); + VERIFY( count != 0 ); + p2.reset(); + VERIFY( count == 0 ); +} + +// Copy construction + +void +test12() +{ + A * const a = new A[2]; + std::shared_ptr p(a); + std::shared_ptr p2(p); + VERIFY( p2.get() == a ); + VERIFY( p.use_count() == 2 ); + VERIFY( p2.use_count() == 2 ); + p.reset(); + VERIFY( count != 0 ); + p2.reset(); + VERIFY( count == 0 ); +} + +void +test13() +{ + A * const a = new A[2]; + std::shared_ptr p(a); + std::shared_ptr p2(p); + VERIFY( p2.get() == a ); + VERIFY( p.use_count() == 2 ); + VERIFY( p2.use_count() == 2 ); + p.reset(); + VERIFY( count != 0 ); + p2.reset(); + VERIFY( count == 0 ); +} + +// Move construction + +void +test14() +{ + A * const a = new A[2]; + std::shared_ptr p(a); + std::shared_ptr p2(std::move(p)); + VERIFY( p.get() == nullptr ); + VERIFY( p2.get() == a ); + VERIFY( p.use_count() == 0 ); + VERIFY( p2.use_count() == 1 ); + p2.reset(); + VERIFY( count == 0 ); +} + +void +test15() +{ + A * const a = new A[2]; + std::shared_ptr p(a); + std::shared_ptr p2(std::move(p)); + VERIFY( p.get() == nullptr ); + VERIFY( p2.get() == a ); + VERIFY( p.use_count() == 0 ); + VERIFY( p2.use_count() == 1 ); + p2.reset(); + VERIFY( count == 0 ); +} + +int +main() +{ + test01(); + test02(); + test03(); + test04(); + test05(); + test06(); + test07(); + test08(); + test09(); + test10(); + test11(); + test12(); + test13(); + test14(); + test15(); +} 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 ); diff --git a/libstdc++-v3/testsuite/20_util/shared_ptr/observers/array.cc b/libstdc++-v3/testsuite/20_util/shared_ptr/observers/array.cc new file mode 100644 index 0000000..c47859d --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/shared_ptr/observers/array.cc @@ -0,0 +1,73 @@ +// { dg-do run { target c++11 } } + +// Copyright (C) 2016 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 +// . + +#include +#include + +struct A +{ + int i = 0; +}; + +// C++1z 20.11.2.2.5 shared_ptr observers [util.smartptr.shared.obs] + +// get +void +test01() +{ + A * const a = new A[2]; + const std::shared_ptr p(a); + VERIFY( p.get() == a ); +} + +// get +void +test02() +{ + A * const a = new A[2]; + const std::shared_ptr p(a); + VERIFY( p.get() == a ); +} + +// operator[] +void +test03() +{ + A * const a = new A[2]; + const std::shared_ptr p(a); + VERIFY( &p[0] == a ); +} + +// operator[] +void +test04() +{ + A * const a = new A[2]; + const std::shared_ptr p(a); + VERIFY( &p[0] == a ); +} + +int +main() +{ + test01(); + test02(); + test03(); + test04(); +}