本文探究在gcc5.4.0中,shared_ptr引用计数的实现
相关源码:
来源:Ubuntu 16
路径:/usr/include/c++/5.4.0/bits
文件:shared_ptr_atomic.h shared_ptr_base.h shared_ptr.h
下面是我精简的shared_ptr类代码,完整的在文末
1 template <typename _Tp> 2 class shared_ptr : public __shared_ptr<_Tp> 3 { 4 5 public: 6 /** 7 * @brief Construct an empty %shared_ptr. 8 * @post use_count()==0 && get()==0 9 */ 10 constexpr shared_ptr() noexcept 11 : __shared_ptr<_Tp>() {} 12 13 shared_ptr(const shared_ptr &) noexcept = default; 14 15 /** 16 * @brief Construct a %shared_ptr that owns the pointer @a __p. 17 * @param __p A pointer that is convertible to element_type*. 18 * @post use_count() == 1 && get() == __p 19 * @throw std::bad_alloc, in which case @c delete @a __p is called. 20 */ 21 template <typename _Tp1> 22 explicit shared_ptr(_Tp1 *__p) 23 : __shared_ptr<_Tp>(__p) {} 24 25 /** 26 * @brief Move-constructs a %shared_ptr instance from @a __r. 27 * @param __r A %shared_ptr rvalue. 28 * @post *this contains the old value of @a __r, @a __r is empty. 29 */ 30 shared_ptr(shared_ptr &&__r) noexcept 31 : __shared_ptr<_Tp>(std::move(__r)) {} 32 33 /** 34 * @brief Constructs a %shared_ptr that shares ownership with @a __r 35 * and stores a copy of the pointer stored in @a __r. 36 * @param __r A weak_ptr. 37 * @post use_count() == __r.use_count() 38 * @throw bad_weak_ptr when __r.expired(), 39 * in which case the constructor has no effect. 40 */ 41 template <typename _Tp1> 42 explicit shared_ptr(const weak_ptr<_Tp1> &__r) 43 : __shared_ptr<_Tp>(__r) {} 44 45 private: 46 47 template <typename _Tp1, typename _Alloc, typename... _Args> 48 friend shared_ptr<_Tp1> 49 allocate_shared(const _Alloc &__a, _Args &&... __args); 50 51 // This constructor is non-standard, it is used by weak_ptr::lock(). 52 shared_ptr(const weak_ptr<_Tp> &__r, std::nothrow_t) 53 : __shared_ptr<_Tp>(__r, std::nothrow) {} 54 55 friend class weak_ptr<_Tp>; 56 };
可以看出来,shared_ptr只是个包装__shared_ptr的类,具体实现需要去看__shared_ptr。除了构造函数和拷贝构造函数,改类还提供了移动语义。
顺带一提,用原始指针初始化shared_ptr在effective modern c++中是不推荐的。原始指针的操作不受引用计数约束,极容易产生原始指针free掉,引用计数大于0的代码,尽量用make_shared初始化是比较好的风格。
下面是__shared_ptr精简后的源码
1 template <typename _Tp, _Lock_policy _Lp> 2 class __shared_ptr 3 : public __shared_ptr_access<_Tp, _Lp> 4 { 5 public: 6 using element_type = typename remove_extent<_Tp>::type; 7 8 private: 9 10 template <typename _Deleter> 11 __shared_ptr(nullptr_t __p, _Deleter __d) 12 : _M_ptr(0), _M_refcount(__p, std::move(__d)) 13 { 14 } 15 16 __shared_ptr(__shared_ptr &&__r) noexcept 17 : _M_ptr(__r._M_ptr), _M_refcount() 18 { 19 _M_refcount._M_swap(__r._M_refcount); 20 __r._M_ptr = 0; 21 } 22 23 24 private: 25 26 element_type *_M_ptr; // Contained pointer. 27 __shared_count<_Lp> _M_refcount; // Reference counter. 28 };
可以看出,引用计数是__shared_count类型。继续看下该类源码,引用计数的底层类型是_Sp_counted_base<_Lp> *
1 template <_Lock_policy _Lp> 2 class __shared_count 3 { 4 public: 5 constexpr __shared_count() noexcept : _M_pi(0) 6 { 7 } 8 9 template <typename _Ptr> 10 explicit __shared_count(_Ptr __p) : _M_pi(0) 11 { 12 __try 13 { 14 _M_pi = new _Sp_counted_ptr<_Ptr, _Lp>(__p); 15 } 16 __catch(...) 17 { 18 delete __p; 19 __throw_exception_again; 20 } 21 } 22 23 private: 24 friend class __weak_count<_Lp>; 25 26 _Sp_counted_base<_Lp> *_M_pi; 27 };
经过上文分析,我们终于找到了use_count的底层实现类。下面我们来看下这个类
1 template <_Lock_policy _Lp = __default_lock_policy> 2 class _Sp_counted_base 3 : public _Mutex_base<_Lp> 4 { 5 public: 6 _Sp_counted_base() noexcept 7 : _M_use_count(1), _M_weak_count(1) {} 8 9 virtual ~_Sp_counted_base() noexcept 10 { 11 } 12 13 // Called when _M_use_count drops to zero, to release the resources 14 // managed by *this. 15 // pusidun注 这里是纯虚函数,必须实现对象的析构。具体的析构需要看下__shared_ptr那里 16 virtual void 17 _M_dispose() noexcept = 0; 18 19 // Called when _M_weak_count drops to zero. 20 virtual void 21 _M_destroy() noexcept 22 { 23 delete this; 24 } 25 26 virtual void * 27 _M_get_deleter(const std::type_info &) noexcept = 0; 28 29 void 30 _M_add_ref_copy() 31 { 32 __gnu_cxx::__atomic_add_dispatch(&_M_use_count, 1); 33 } 34 35 void 36 _M_add_ref_lock(); 37 38 bool 39 _M_add_ref_lock_nothrow(); 40 41 void 42 _M_release() noexcept 43 { 44 // Be race-detector-friendly. For more info see bits/c++config. 45 _GLIBCXX_SYNCHRONIZATION_HAPPENS_BEFORE(&_M_use_count); 46 // pusidun注 这里是原子操作,先_M_use_count-1,然后检查_M_use_count减掉1之前是否是1 47 // 是1说明现在引用计数已经降为0了,调用_M_dispose析构掉持有对象 48 if (__gnu_cxx::__exchange_and_add_dispatch(&_M_use_count, -1) == 1) 49 { 50 _GLIBCXX_SYNCHRONIZATION_HAPPENS_AFTER(&_M_use_count); 51 _M_dispose(); 52 // There must be a memory barrier between dispose() and destroy() 53 // to ensure that the effects of dispose() are observed in the 54 // thread that runs destroy(). 55 // See http://gcc.gnu.org/ml/libstdc++/2005-11/msg00136.html 56 if (_Mutex_base<_Lp>::_S_need_barriers) 57 { 58 __atomic_thread_fence(__ATOMIC_ACQ_REL); 59 } 60 61 // Be race-detector-friendly. For more info see bits/c++config. 62 _GLIBCXX_SYNCHRONIZATION_HAPPENS_BEFORE(&_M_weak_count); 63 if (__gnu_cxx::__exchange_and_add_dispatch(&_M_weak_count, 64 -1) == 1) 65 { 66 _GLIBCXX_SYNCHRONIZATION_HAPPENS_AFTER(&_M_weak_count); 67 _M_destroy(); 68 } 69 } 70 } 71 72 void 73 _M_weak_add_ref() noexcept 74 { 75 __gnu_cxx::__atomic_add_dispatch(&_M_weak_count, 1); 76 } 77 78 void 79 _M_weak_release() noexcept 80 { 81 // Be race-detector-friendly. For more info see bits/c++config. 82 _GLIBCXX_SYNCHRONIZATION_HAPPENS_BEFORE(&_M_weak_count); 83 if (__gnu_cxx::__exchange_and_add_dispatch(&_M_weak_count, -1) == 1) 84 { 85 _GLIBCXX_SYNCHRONIZATION_HAPPENS_AFTER(&_M_weak_count); 86 if (_Mutex_base<_Lp>::_S_need_barriers) 87 { 88 // See _M_release(), 89 // destroy() must observe results of dispose() 90 __atomic_thread_fence(__ATOMIC_ACQ_REL); 91 } 92 _M_destroy(); 93 } 94 } 95 96 long 97 _M_get_use_count() const noexcept 98 { 99 // No memory barrier is used here so there is no synchronization 100 // with other threads. 101 return __atomic_load_n(&_M_use_count, __ATOMIC_RELAXED); 102 } 103 104 private: 105 _Sp_counted_base(_Sp_counted_base const &) = delete; 106 _Sp_counted_base &operator=(_Sp_counted_base const &) = delete; 107 108 _Atomic_word _M_use_count; // #shared 109 _Atomic_word _M_weak_count; // #weak + (#shared != 0) 110 };
重点是42行的_M_release() 方法。
该方法中,对use_count进行增减、比较是原子操作。这就说明,在多线程中,shared_ptr的引用计数本身是线程安全的。但是,_M_dispose()的线程安全性却无法得到保证(并没有同步措施处理data race情况)。也就是说,shared_ptr管理的内存,在多线程环境下需要关注析构细节。
1 template <typename _Tp> 2 class shared_ptr : public __shared_ptr<_Tp> 3 { 4 template <typename _Ptr> 5 using _Convertible = typename enable_if<is_convertible<_Ptr, _Tp *>::value>::type; 6 7 public: 8 /** 9 * @brief Construct an empty %shared_ptr. 10 * @post use_count()==0 && get()==0 11 */ 12 constexpr shared_ptr() noexcept 13 : __shared_ptr<_Tp>() {} 14 15 shared_ptr(const shared_ptr &) noexcept = default; 16 17 /** 18 * @brief Construct a %shared_ptr that owns the pointer @a __p. 19 * @param __p A pointer that is convertible to element_type*. 20 * @post use_count() == 1 && get() == __p 21 * @throw std::bad_alloc, in which case @c delete @a __p is called. 22 */ 23 template <typename _Tp1> 24 explicit shared_ptr(_Tp1 *__p) 25 : __shared_ptr<_Tp>(__p) {} 26 27 /** 28 * @brief Construct a %shared_ptr that owns the pointer @a __p 29 * and the deleter @a __d. 30 * @param __p A pointer. 31 * @param __d A deleter. 32 * @post use_count() == 1 && get() == __p 33 * @throw std::bad_alloc, in which case @a __d(__p) is called. 34 * 35 * Requirements: _Deleter's copy constructor and destructor must 36 * not throw 37 * 38 * __shared_ptr will release __p by calling __d(__p) 39 */ 40 template <typename _Tp1, typename _Deleter> 41 shared_ptr(_Tp1 *__p, _Deleter __d) 42 : __shared_ptr<_Tp>(__p, __d) {} 43 44 /** 45 * @brief Construct a %shared_ptr that owns a null pointer 46 * and the deleter @a __d. 47 * @param __p A null pointer constant. 48 * @param __d A deleter. 49 * @post use_count() == 1 && get() == __p 50 * @throw std::bad_alloc, in which case @a __d(__p) is called. 51 * 52 * Requirements: _Deleter's copy constructor and destructor must 53 * not throw 54 * 55 * The last owner will call __d(__p) 56 */ 57 template <typename _Deleter> 58 shared_ptr(nullptr_t __p, _Deleter __d) 59 : __shared_ptr<_Tp>(__p, __d) {} 60 61 /** 62 * @brief Construct a %shared_ptr that owns the pointer @a __p 63 * and the deleter @a __d. 64 * @param __p A pointer. 65 * @param __d A deleter. 66 * @param __a An allocator. 67 * @post use_count() == 1 && get() == __p 68 * @throw std::bad_alloc, in which case @a __d(__p) is called. 69 * 70 * Requirements: _Deleter's copy constructor and destructor must 71 * not throw _Alloc's copy constructor and destructor must not 72 * throw. 73 * 74 * __shared_ptr will release __p by calling __d(__p) 75 */ 76 template <typename _Tp1, typename _Deleter, typename _Alloc> 77 shared_ptr(_Tp1 *__p, _Deleter __d, _Alloc __a) 78 : __shared_ptr<_Tp>(__p, __d, std::move(__a)) {} 79 80 /** 81 * @brief Construct a %shared_ptr that owns a null pointer 82 * and the deleter @a __d. 83 * @param __p A null pointer constant. 84 * @param __d A deleter. 85 * @param __a An allocator. 86 * @post use_count() == 1 && get() == __p 87 * @throw std::bad_alloc, in which case @a __d(__p) is called. 88 * 89 * Requirements: _Deleter's copy constructor and destructor must 90 * not throw _Alloc's copy constructor and destructor must not 91 * throw. 92 * 93 * The last owner will call __d(__p) 94 */ 95 template <typename _Deleter, typename _Alloc> 96 shared_ptr(nullptr_t __p, _Deleter __d, _Alloc __a) 97 : __shared_ptr<_Tp>(__p, __d, std::move(__a)) {} 98 99 // Aliasing constructor 100 101 /** 102 * @brief Constructs a %shared_ptr instance that stores @a __p 103 * and shares ownership with @a __r. 104 * @param __r A %shared_ptr. 105 * @param __p A pointer that will remain valid while @a *__r is valid. 106 * @post get() == __p && use_count() == __r.use_count() 107 * 108 * This can be used to construct a @c shared_ptr to a sub-object 109 * of an object managed by an existing @c shared_ptr. 110 * 111 * @code 112 * shared_ptr< pair<int,int> > pii(new pair<int,int>()); 113 * shared_ptr<int> pi(pii, &pii->first); 114 * assert(pii.use_count() == 2); 115 * @endcode 116 */ 117 template <typename _Tp1> 118 shared_ptr(const shared_ptr<_Tp1> &__r, _Tp *__p) noexcept 119 : __shared_ptr<_Tp>(__r, __p) {} 120 121 /** 122 * @brief If @a __r is empty, constructs an empty %shared_ptr; 123 * otherwise construct a %shared_ptr that shares ownership 124 * with @a __r. 125 * @param __r A %shared_ptr. 126 * @post get() == __r.get() && use_count() == __r.use_count() 127 */ 128 template <typename _Tp1, typename = _Convertible<_Tp1 *>> 129 shared_ptr(const shared_ptr<_Tp1> &__r) noexcept 130 : __shared_ptr<_Tp>(__r) {} 131 132 /** 133 * @brief Move-constructs a %shared_ptr instance from @a __r. 134 * @param __r A %shared_ptr rvalue. 135 * @post *this contains the old value of @a __r, @a __r is empty. 136 */ 137 shared_ptr(shared_ptr &&__r) noexcept 138 : __shared_ptr<_Tp>(std::move(__r)) {} 139 140 /** 141 * @brief Move-constructs a %shared_ptr instance from @a __r. 142 * @param __r A %shared_ptr rvalue. 143 * @post *this contains the old value of @a __r, @a __r is empty. 144 */ 145 template <typename _Tp1, typename = _Convertible<_Tp1 *>> 146 shared_ptr(shared_ptr<_Tp1> &&__r) noexcept 147 : __shared_ptr<_Tp>(std::move(__r)) {} 148 149 /** 150 * @brief Constructs a %shared_ptr that shares ownership with @a __r 151 * and stores a copy of the pointer stored in @a __r. 152 * @param __r A weak_ptr. 153 * @post use_count() == __r.use_count() 154 * @throw bad_weak_ptr when __r.expired(), 155 * in which case the constructor has no effect. 156 */ 157 template <typename _Tp1> 158 explicit shared_ptr(const weak_ptr<_Tp1> &__r) 159 : __shared_ptr<_Tp>(__r) {} 160 161 #if _GLIBCXX_USE_DEPRECATED 162 template <typename _Tp1> 163 shared_ptr(std::auto_ptr<_Tp1> &&__r); 164 #endif 165 166 // _GLIBCXX_RESOLVE_LIB_DEFECTS 167 // 2399. shared_ptr's constructor from unique_ptr should be constrained 168 template <typename _Tp1, typename _Del, typename = _Convertible<typename unique_ptr<_Tp1, _Del>::pointer>> 169 shared_ptr(std::unique_ptr<_Tp1, _Del> &&__r) 170 : __shared_ptr<_Tp>(std::move(__r)) {} 171 172 /** 173 * @brief Construct an empty %shared_ptr. 174 * @post use_count() == 0 && get() == nullptr 175 */ 176 constexpr shared_ptr(nullptr_t) noexcept : shared_ptr() {} 177 178 shared_ptr &operator=(const shared_ptr &) noexcept = default; 179 180 template <typename _Tp1> 181 shared_ptr & 182 operator=(const shared_ptr<_Tp1> &__r) noexcept 183 { 184 this->__shared_ptr<_Tp>::operator=(__r); 185 return *this; 186 } 187 188 #if _GLIBCXX_USE_DEPRECATED 189 template <typename _Tp1> 190 shared_ptr & 191 operator=(std::auto_ptr<_Tp1> &&__r) 192 { 193 this->__shared_ptr<_Tp>::operator=(std::move(__r)); 194 return *this; 195 } 196 #endif 197 198 shared_ptr & 199 operator=(shared_ptr &&__r) noexcept 200 { 201 this->__shared_ptr<_Tp>::operator=(std::move(__r)); 202 return *this; 203 } 204 205 template <class _Tp1> 206 shared_ptr & 207 operator=(shared_ptr<_Tp1> &&__r) noexcept 208 { 209 this->__shared_ptr<_Tp>::operator=(std::move(__r)); 210 return *this; 211 } 212 213 template <typename _Tp1, typename _Del> 214 shared_ptr & 215 operator=(std::unique_ptr<_Tp1, _Del> &&__r) 216 { 217 this->__shared_ptr<_Tp>::operator=(std::move(__r)); 218 return *this; 219 } 220 221 private: 222 // This constructor is non-standard, it is used by allocate_shared. 223 template <typename _Alloc, typename... _Args> 224 shared_ptr(_Sp_make_shared_tag __tag, const _Alloc &__a, 225 _Args &&... __args) 226 : __shared_ptr<_Tp>(__tag, __a, std::forward<_Args>(__args)...) 227 { 228 } 229 230 template <typename _Tp1, typename _Alloc, typename... _Args> 231 friend shared_ptr<_Tp1> 232 allocate_shared(const _Alloc &__a, _Args &&... __args); 233 234 // This constructor is non-standard, it is used by weak_ptr::lock(). 235 shared_ptr(const weak_ptr<_Tp> &__r, std::nothrow_t) 236 : __shared_ptr<_Tp>(__r, std::nothrow) {} 237 238 friend class weak_ptr<_Tp>; 239 };
1 template <typename _Tp, _Lock_policy _Lp> 2 class __shared_ptr 3 : public __shared_ptr_access<_Tp, _Lp> 4 { 5 public: 6 using element_type = typename remove_extent<_Tp>::type; 7 8 private: 9 // Constraint for taking ownership of a pointer of type _Yp*: 10 template <typename _Yp> 11 using _SafeConv = typename enable_if<__sp_is_constructible<_Tp, _Yp>::value>::type; 12 13 // Constraint for construction from shared_ptr and weak_ptr: 14 template <typename _Yp, typename _Res = void> 15 using _Compatible = typename enable_if<__sp_compatible_with<_Yp *, _Tp *>::value, _Res>::type; 16 17 // Constraint for assignment from shared_ptr and weak_ptr: 18 template <typename _Yp> 19 using _Assignable = _Compatible<_Yp, __shared_ptr &>; 20 21 // Constraint for construction from unique_ptr: 22 template <typename _Yp, typename _Del, typename _Res = void, 23 typename _Ptr = typename unique_ptr<_Yp, _Del>::pointer> 24 using _UniqCompatible = typename enable_if<__and_< 25 __sp_compatible_with<_Yp *, _Tp *>, is_convertible<_Ptr, element_type *>>::value, 26 _Res>::type; 27 28 // Constraint for assignment from unique_ptr: 29 template <typename _Yp, typename _Del> 30 using _UniqAssignable = _UniqCompatible<_Yp, _Del, __shared_ptr &>; 31 32 public: 33 #if __cplusplus > 201402L 34 using weak_type = __weak_ptr<_Tp, _Lp>; 35 #endif 36 37 constexpr __shared_ptr() noexcept 38 : _M_ptr(0), _M_refcount() 39 { 40 } 41 42 template <typename _Yp, typename = _SafeConv<_Yp>> 43 explicit __shared_ptr(_Yp *__p) 44 : _M_ptr(__p), _M_refcount(__p, typename is_array<_Tp>::type()) 45 { 46 static_assert(!is_void<_Yp>::value, "incomplete type"); 47 static_assert(sizeof(_Yp) > 0, "incomplete type"); 48 _M_enable_shared_from_this_with(__p); 49 } 50 51 template <typename _Yp, typename _Deleter, typename = _SafeConv<_Yp>> 52 __shared_ptr(_Yp *__p, _Deleter __d) 53 : _M_ptr(__p), _M_refcount(__p, std::move(__d)) 54 { 55 static_assert(__is_invocable<_Deleter &, _Yp *&>::value, 56 "deleter expression d(p) is well-formed"); 57 _M_enable_shared_from_this_with(__p); 58 } 59 60 template <typename _Yp, typename _Deleter, typename _Alloc, 61 typename = _SafeConv<_Yp>> 62 __shared_ptr(_Yp *__p, _Deleter __d, _Alloc __a) 63 : _M_ptr(__p), _M_refcount(__p, std::move(__d), std::move(__a)) 64 { 65 static_assert(__is_invocable<_Deleter &, _Yp *&>::value, 66 "deleter expression d(p) is well-formed"); 67 _M_enable_shared_from_this_with(__p); 68 } 69 70 template <typename _Deleter> 71 __shared_ptr(nullptr_t __p, _Deleter __d) 72 : _M_ptr(0), _M_refcount(__p, std::move(__d)) 73 { 74 } 75 76 template <typename _Deleter, typename _Alloc> 77 __shared_ptr(nullptr_t __p, _Deleter __d, _Alloc __a) 78