[GSoC] Extend shared_ptr to support array, update 2

Fan You youfan.noey@gmail.com
Sun Apr 5 00:26:00 GMT 2015


Hello,

Things I've tried recently, by adding specialization for
__shared_ptr<__libfund_v1<T>>
 - [8.2.1.1] shared_ptr constructors.
 - [8.2.1.2] shared_ptr observers.
 - Change element_type in __weak_ptr to remove_extent<_Tp>::type;
 - According to
<http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3641.html>,
I overload make_shared and allocate_shared with an extra parameter
(size_t __size) to support allocate memory for array type. However,
it's not in the standard, am I allow to do this?
 - And I am also worried about the support for N-dimension array. The
deleter seems to be fine, but something like shared_ptr<T[N][]...>,
shared_ptr<T[][N]...> or shared_ptr<T[][]...> may or may not cause
extra works. Or should I just not consider these for now?

I've write simple test case to test all the things I've implement, but
they are not yet tested by gcc testsuit.

Things that remained to be done are pointer_cast, I am not sure about
" It could be sacrificed if necessary" in the proposal
<http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3920.html>.
However, the reset seems to be fine by add __libfund_v1. I will
continue working on this, any comments are welcome.

Thanks : )

Fan

(Code are attached.)
-------------- next part --------------
--- a/bits/shared_ptr_base.h
+++ b/bits/shared_ptr_base.h
@@ -1,3 +1,5 @@
 // shared_ptr and weak_ptr implementation details -*- C++ -*-
 
 // Copyright (C) 2007-2014 Free Software Foundation, Inc.
@@ -627,6 +629,29 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	    }
 	}
 
+      template<typename _Tp, typename _Alloc, typename... _Args>
+	__shared_count(_Sp_make_shared_tag, _Tp*, const _Alloc& __a,
+		       size_t __size, _Args&&... __args)
+	: _M_pi(0)
+	{
+	  typedef _Sp_counted_ptr_inplace<_Tp, _Alloc, _Lp> _Sp_cp_type;
+	  typedef typename allocator_traits<_Alloc>::template
+	    rebind_traits<_Sp_cp_type> _Alloc_traits;
+	  typename _Alloc_traits::allocator_type __a2(__a);
+	  _Sp_cp_type* __mem = _Alloc_traits::allocate(__a2, __size);
+	  __try
+	    {
+	      _Alloc_traits::construct(__a2, __mem, std::move(__a),
+		    std::forward<_Args>(__args)...);
+	      _M_pi = __mem;
+	    }
+	  __catch(...)
+	    {
+	      _Alloc_traits::deallocate(__a2, __mem, __size);
+	      __throw_exception_again;
+	    }
+	}
+
 #if _GLIBCXX_USE_DEPRECATED
       // Special case for auto_ptr<_Tp> to provide the strong guarantee.
       template<typename _Tp>
@@ -1175,6 +1200,123 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       __shared_count<_Lp>  _M_refcount;    // Reference counter.
     };
 
+  //new array  approach
+  template <typename _Tp>
+    struct __libfund_v1 {using type = _Tp;};
+
+  //array support revised
+  template<typename _Tp, _Lock_policy _Lp, unsigned N>
+    class __shared_ptr<__libfund_v1<_Tp[N]>, _Lp>
+    {
+    public:
+      using element_type = typename __libfund_v1<_Tp[N]>::type;
+
+      constexpr __shared_ptr() = default;
+
+      template<typename _Tp1>
+        explicit __shared_ptr(_Tp1* __p) 
+        : _M_ptr(__p), _M_refcount(__p, _M_del) // default deleter
+        {
+          __glibcxx_function_requires(_ConvertibleConcept<_Tp1*, _Tp*>)
+          static_assert( !is_void<_Tp1>::value, "incomplete type" );
+          static_assert( sizeof(_Tp1) > 0, "incomplete type" );
+          // enable shared
+          __enable_shared_from_this_helper(_M_refcount, __p, __p);
+        }
+
+      template<typename _Tp1, typename _Deleter>
+        __shared_ptr(_Tp1* __p, _Deleter __d)
+        : _M_ptr(__p), _M_refcount(__p, __d) // custom deleter // nullptr
+        {
+          __glibcxx_function_requires(_ConvertibleConcept<_Tp1*, _Tp*>)
+          // enable shared
+          __enable_shared_from_this_helper(_M_refcount, __p, __p);
+        }
+
+      template<typename _Tp1, typename _Deleter, typename _Alloc>
+	__shared_ptr(_Tp1* __p, _Deleter __d, _Alloc __a)
+	: _M_ptr(__p), _M_refcount(__p, __d, std::move(__a))
+	{
+	  __glibcxx_function_requires(_ConvertibleConcept<_Tp1*, _Tp*>)
+	  __enable_shared_from_this_helper(_M_refcount, __p, __p);
+	} 
+
+      template<typename _Tp1>
+	__shared_ptr(const __shared_ptr<__libfund_v1<_Tp1>, _Lp>& __r, _Tp* __p) noexcept
+	: _M_ptr(__p), _M_refcount(__r._M_refcount)
+	{ }
+
+      template<typename _Tp1>
+        explicit __shared_ptr(const __weak_ptr<_Tp1, _Lp>& __r)
+        : _M_refcount(__r._M_refcount) // may throw
+        {
+          __glibcxx_function_requires(_ConvertibleConcept<_Tp1*, _Tp*>)
+          _M_ptr = __r._M_ptr;
+        }
+
+      ~__shared_ptr() = default;
+
+      //observers
+      _Tp*
+      get() const noexcept
+      {return _M_ptr;}
+
+      long
+      use_count() const noexcept
+      { return _M_refcount._M_get_use_count(); }
+
+      __shared_ptr(const __weak_ptr<_Tp[], _Lp>& __r, std::nothrow_t)
+      : _M_refcount(__r._M_refcount, std::nothrow)
+      {
+         _M_ptr = _M_refcount._M_get_use_count() ?
+         __r._M_ptr : nullptr;
+      }
+
+    protected:
+
+      template<typename _Alloc, typename... _Args>
+	__shared_ptr(_Sp_make_shared_tag __tag, const _Alloc& __a,
+		     size_t __size, _Args&&... __args)
+	: _M_ptr(), _M_refcount(__tag, (_Tp*)0, __a, __size,
+				std::forward<_Args>(__args)...)
+	{ 
+	  void* __p = _M_refcount._M_get_deleter(typeid(__tag)); //Get the right deleter? TODO
+	  _M_ptr = static_cast<_Tp*>(__p);
+	  __enable_shared_from_this_helper(_M_refcount, _M_ptr, _M_ptr);
+	}
+
+      struct _D_Deleter
+      {
+        void
+        operator()(_Tp const *__p)
+        {
+          delete [] __p;
+        }
+      };
+
+    private:
+
+      void*
+      _M_get_deleter(const std::type_info& __ti) const noexcept
+      {return _M_refcount._M_get_deleter(__ti); }
+
+      template<typename _Tp1, _Lock_policy _Lp1> friend class __weak_ptr;
+      template<typename _Tp1, _Lock_policy _Lp1> friend class __shared_ptr;
+
+      template<typename _Del, typename _Tp1, _Lock_policy _Lp1>
+	friend _Del* get_deleter(const __shared_ptr<_Tp1, _Lp1>&) noexcept;
+
+      _Tp*		  _M_ptr;	//ptr
+      _D_Deleter          _M_del;	//default destructor
+      __shared_count<_Lp> _M_refcount;	//ref counter
+    };
+
 
   // 20.7.2.2.7 shared_ptr comparisons
   template<typename _Tp1, typename _Tp2, _Lock_policy _Lp>
@@ -1334,12 +1476,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       return __shared_ptr<_Tp, _Lp>();
     }
 
-
   template<typename _Tp, _Lock_policy _Lp>
     class __weak_ptr
     {
     public:
-      typedef _Tp element_type;
+
+      using element_type = typename remove_extent<_Tp>::type;
 
       constexpr __weak_ptr() noexcept
       : _M_ptr(0), _M_refcount()
@@ -1440,7 +1582,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       friend class __enable_shared_from_this<_Tp, _Lp>;
       friend class enable_shared_from_this<_Tp>;
 
-      _Tp*	 	 _M_ptr;         // Contained pointer.
+      element_type*	 _M_ptr;         // Contained pointer.
       __weak_count<_Lp>  _M_refcount;    // Reference counter.
     };
 
diff --git a/experimental/memory b/experimental/memory
new file mode 100644
index 0000000..1c2328f
--- /dev/null
+++ b/experimental/memory
@@ -0,0 +1,120 @@
+#include <memory>
+
+namespace std {
+namespace experimental {
+inline namespace fundamentals_v1 {
+
+  template<typename _Tp>
+    class shared_ptr;
+
+  // C++14 §20.8.2.2.6
+  // According to proposal
+  template<typename _Tp, typename _Alloc, typename... _Args>
+    inline shared_ptr<_Tp>
+    allocate_shared(const _Alloc& __a, size_t __size, _Args&&... __args)
+    {
+      return shared_ptr<_Tp>(_Sp_make_shared_tag(), __a, __size,
+			     std::forward<_Args>(__args)...);
+    }
+  
+  template<typename _Tp, typename _Alloc, typename... _Args>
+    inline shared_ptr<_Tp>
+    allocate_shared(const _Alloc& __a, _Args&&... __args)
+    {
+      return shared_ptr<_Tp>(_Sp_make_shared_tag(), __a,
+			     std::forward<_Args>(__args)...);
+    }
+
+  template<typename _Tp, typename... _Args>
+    inline shared_ptr<_Tp>
+    make_shared(size_t __size, _Args&&... __args)
+    {
+      typedef typename std::remove_const<std::remove_extent<_Tp>>::type _Tp_nc;
+      return std::experimental::allocate_shared<_Tp>(std::allocator<_Tp_nc>(), __size, 
+						    std::forward<_Args>(__args)...);
+    }
+
+  template<typename _Tp, typename... _Args>
+    inline shared_ptr<_Tp>
+    make_shared(_Args&&... __args)
+    {
+      typedef typename std::remove_const<std::remove_extent<_Tp>>::type _Tp_nc;
+      return std::experimental::allocate_shared<_Tp>(std::allocator<_Tp_nc>(),
+						     std::forward<_Args>(__args)...);
+    }
+
+  //for non default lock policy
+  template<typename _Tp, _Lock_policy _Lp = __default_lock_policy>
+    using __shared_ptr = std::__shared_ptr<_Tp, _Lp>;
+
+  template<typename _Tp, unsigned N>
+    class shared_ptr<_Tp[N]> : public __shared_ptr<__libfund_v1<_Tp[N]>>
+    {
+    public:
+      typedef typename remove_extent_t<_Tp> element_type;
+
+      constexpr shared_ptr() noexcept = default;
+
+      template<typename _Tp1>
+        explicit shared_ptr(_Tp1* __p) : __shared_ptr<__libfund_v1<_Tp[N]>>(__p) { }
+
+      template<typename _Tp1, typename _Deleter> 
+        shared_ptr(_Tp1* __p, _Deleter __d)
+        : __shared_ptr<__libfund_v1<_Tp[N]>>(__p, __d) { }
+
+      template<typename _Tp1, typename _Deleter, typename _Alloc> 
+        shared_ptr(_Tp1* __p, _Deleter __d, _Alloc __a)
+        : __shared_ptr<__libfund_v1<_Tp[N]>>(__p, __d, __a) { }
+
+      template<typename _Deleter> // N = 0 ?
+        shared_ptr(nullptr_t __p, _Deleter __d)
+        : __shared_ptr<__libfund_v1<_Tp[N]>>(__p, __d) { }
+
+      template<typename _Deleter, typename _Alloc> // N = 0 ?
+        shared_ptr(nullptr_t __p, _Deleter __d, _Alloc __a)
+        : __shared_ptr<__libfund_v1<_Tp[N]>>(__p, __d, __a) { }
+
+      template<typename _Tp1> // _Tp1 is not array type?
+        shared_ptr(const shared_ptr<_Tp1>& __r, _Tp* __p) noexcept
+        : __shared_ptr<__libfund_v1<_Tp[N]>>(__r, __p) { }
+
+      shared_ptr(const shared_ptr<_Tp>&& __r) noexcept
+      : __shared_ptr<__libfund_v1<_Tp[N]>>(std::move(__r)) { }
+
+      //TODO 32
+      //TODO cast
+
+      ~shared_ptr() = default;
+
+      // C++14 §20.8.2.3
+      template<typename _Tp1>
+        explicit shared_ptr(const weak_ptr<_Tp1>& __r)
+        : __shared_ptr<_Tp[N]>(__r){ }
+
+      // Observers
+      _Tp& 
+      operator[](ptrdiff_t i) const noexcept
+      {
+	return (this->get())[i];
+      }
+
+    private:
+      // non standard for make_shared
+      template<typename _Alloc, typename... _Args>
+      shared_ptr(_Sp_make_shared_tag __tag, const _Alloc& __a,
+		 size_t __size = N, _Args&&... __args)
+      : __shared_ptr<__libfund_v1<_Tp[N]>>(__tag, __a, __size,
+					   std::forward<_Args>(__args)...)
+      { }
+
+      template<typename _Tp1, typename _Alloc, typename... _Args>
+	friend shared_ptr<_Tp1>
+	allocate_shared(const _Alloc& __a, size_t __size, _Args&&... __args);
+
+      template<typename _Tp1, typename _Alloc, typename... _Args>
+	friend shared_ptr<_Tp1>
+	allocate_shared(const _Alloc& __a, _Args&&... __args);
+    };
+}
+}
+}


More information about the Libstdc++ mailing list