今晚跟同窗談了一下智能指針,忽然想要看一下C++11的智能指針的實現,所以下了這篇博文。安全
如下代碼出自於VS2012 <memory>多線程
1 template<class _Ty> 2 class shared_ptr 3 : public _Ptr_base<_Ty> 4 { // class for reference counted resource management 5 public: 6 typedef shared_ptr<_Ty> _Myt; 7 typedef _Ptr_base<_Ty> _Mybase; 8 9 shared_ptr() _NOEXCEPT 10 { // construct empty shared_ptr object 11 } 12 13 template<class _Ux> 14 explicit shared_ptr(_Ux *_Px) 15 { // construct shared_ptr object that owns _Px 16 _Resetp(_Px); 17 } 18 19 template<class _Ux, 20 class _Dx> 21 shared_ptr(_Ux *_Px, _Dx _Dt) 22 { // construct with _Px, deleter 23 _Resetp(_Px, _Dt); 24 } 25 26 //#if _HAS_CPP0X 27 28 shared_ptr(nullptr_t) 29 { // construct with nullptr 30 _Resetp((_Ty *)0); 31 } 32 33 template<class _Dx> 34 shared_ptr(nullptr_t, _Dx _Dt) 35 { // construct with nullptr, deleter 36 _Resetp((_Ty *)0, _Dt); 37 } 38 39 template<class _Dx, 40 class _Alloc> 41 shared_ptr(nullptr_t, _Dx _Dt, _Alloc _Ax) 42 { // construct with nullptr, deleter, allocator 43 _Resetp((_Ty *)0, _Dt, _Ax); 44 } 45 46 template<class _Ux, 47 class _Dx, 48 class _Alloc> 49 shared_ptr(_Ux *_Px, _Dx _Dt, _Alloc _Ax) 50 { // construct with _Px, deleter, allocator 51 _Resetp(_Px, _Dt, _Ax); 52 } 53 //#endif /* _HAS_CPP0X */ 54 55 #if _HAS_CPP0X 56 template<class _Ty2> 57 shared_ptr(const shared_ptr<_Ty2>& _Right, _Ty *_Px) _NOEXCEPT 58 { // construct shared_ptr object that aliases _Right 59 this->_Reset(_Px, _Right); 60 } 61 #endif /* _HAS_CPP0X */ 62 63 shared_ptr(const _Myt& _Other) _NOEXCEPT 64 { // construct shared_ptr object that owns same resource as _Other 65 this->_Reset(_Other); 66 } 67 68 template<class _Ty2> 69 shared_ptr(const shared_ptr<_Ty2>& _Other, 70 typename enable_if<is_convertible<_Ty2 *, _Ty *>::value, 71 void>::type ** = 0) _NOEXCEPT 72 { // construct shared_ptr object that owns same resource as _Other 73 this->_Reset(_Other); 74 } 75 76 template<class _Ty2> 77 explicit shared_ptr(const weak_ptr<_Ty2>& _Other, 78 bool _Throw = true) 79 { // construct shared_ptr object that owns resource *_Other 80 this->_Reset(_Other, _Throw); 81 } 82 83 template<class _Ty2> 84 shared_ptr(auto_ptr<_Ty2>&& _Other) 85 { // construct shared_ptr object that owns *_Other.get() 86 this->_Reset(_STD move(_Other)); 87 } 88 89 template<class _Ty2> 90 shared_ptr(const shared_ptr<_Ty2>& _Other, const _Static_tag& _Tag) 91 { // construct shared_ptr object for static_pointer_cast 92 this->_Reset(_Other, _Tag); 93 } 94 95 template<class _Ty2> 96 shared_ptr(const shared_ptr<_Ty2>& _Other, const _Const_tag& _Tag) 97 { // construct shared_ptr object for const_pointer_cast 98 this->_Reset(_Other, _Tag); 99 } 100 101 template<class _Ty2> 102 shared_ptr(const shared_ptr<_Ty2>& _Other, const _Dynamic_tag& _Tag) 103 { // construct shared_ptr object for dynamic_pointer_cast 104 this->_Reset(_Other, _Tag); 105 } 106 107 shared_ptr(_Myt&& _Right) _NOEXCEPT 108 : _Mybase(_STD forward<_Myt>(_Right)) 109 { // construct shared_ptr object that takes resource from _Right 110 } 111 112 template<class _Ty2> 113 shared_ptr(shared_ptr<_Ty2>&& _Right, 114 typename enable_if<is_convertible<_Ty2 *, _Ty *>::value, 115 void>::type ** = 0) _NOEXCEPT 116 : _Mybase(_STD forward<shared_ptr<_Ty2> >(_Right)) 117 { // construct shared_ptr object that takes resource from _Right 118 } 119 120 #if _HAS_CPP0X 121 template<class _Ux, 122 class _Dx> 123 shared_ptr(unique_ptr<_Ux, _Dx>&& _Right) 124 { // construct from unique_ptr 125 _Resetp(_Right.release(), _Right.get_deleter()); 126 } 127 128 template<class _Ux, 129 class _Dx> 130 _Myt& operator=(unique_ptr<_Ux, _Dx>&& _Right) 131 { // move from unique_ptr 132 shared_ptr(_STD move(_Right)).swap(*this); 133 return (*this); 134 } 135 #endif /* _HAS_CPP0X */ 136 137 _Myt& operator=(_Myt&& _Right) _NOEXCEPT 138 { // construct shared_ptr object that takes resource from _Right 139 shared_ptr(_STD move(_Right)).swap(*this); 140 return (*this); 141 } 142 143 template<class _Ty2> 144 _Myt& operator=(shared_ptr<_Ty2>&& _Right) _NOEXCEPT 145 { // construct shared_ptr object that takes resource from _Right 146 shared_ptr(_STD move(_Right)).swap(*this); 147 return (*this); 148 } 149 150 ~shared_ptr() _NOEXCEPT 151 { // release resource 152 this->_Decref(); 153 } 154 155 _Myt& operator=(const _Myt& _Right) _NOEXCEPT 156 { // assign shared ownership of resource owned by _Right 157 shared_ptr(_Right).swap(*this); 158 return (*this); 159 } 160 161 template<class _Ty2> 162 _Myt& operator=(const shared_ptr<_Ty2>& _Right) _NOEXCEPT 163 { // assign shared ownership of resource owned by _Right 164 shared_ptr(_Right).swap(*this); 165 return (*this); 166 } 167 168 template<class _Ty2> 169 _Myt& operator=(auto_ptr<_Ty2>&& _Right) 170 { // assign ownership of resource pointed to by _Right 171 shared_ptr(_STD move(_Right)).swap(*this); 172 return (*this); 173 } 174 175 void reset() _NOEXCEPT 176 { // release resource and convert to empty shared_ptr object 177 shared_ptr().swap(*this); 178 } 179 180 template<class _Ux> 181 void reset(_Ux *_Px) 182 { // release, take ownership of _Px 183 shared_ptr(_Px).swap(*this); 184 } 185 186 template<class _Ux, 187 class _Dx> 188 void reset(_Ux *_Px, _Dx _Dt) 189 { // release, take ownership of _Px, with deleter _Dt 190 shared_ptr(_Px, _Dt).swap(*this); 191 } 192 193 //#if _HAS_CPP0X 194 template<class _Ux, 195 class _Dx, 196 class _Alloc> 197 void reset(_Ux *_Px, _Dx _Dt, _Alloc _Ax) 198 { // release, take ownership of _Px, with deleter _Dt, allocator _Ax 199 shared_ptr(_Px, _Dt, _Ax).swap(*this); 200 } 201 //#endif /* _HAS_CPP0X */ 202 203 void swap(_Myt& _Other) _NOEXCEPT 204 { // swap pointers 205 this->_Swap(_Other); 206 } 207 208 _Ty *get() const _NOEXCEPT 209 { // return pointer to resource 210 return (this->_Get()); 211 } 212 213 typename add_reference<_Ty>::type operator*() const _NOEXCEPT 214 { // return reference to resource 215 return (*this->_Get()); 216 } 217 218 _Ty *operator->() const _NOEXCEPT 219 { // return pointer to resource 220 return (this->_Get()); 221 } 222 223 bool unique() const _NOEXCEPT 224 { // return true if no other shared_ptr object owns this resource 225 return (this->use_count() == 1); 226 } 227 228 _TYPEDEF_BOOL_TYPE; 229 230 _OPERATOR_BOOL() const _NOEXCEPT 231 { // test if shared_ptr object owns no resource 232 return (this->_Get() != 0 ? _CONVERTIBLE_TO_TRUE : 0); 233 } 234 235 private: 236 template<class _Ux> 237 void _Resetp(_Ux *_Px) 238 { // release, take ownership of _Px 239 _TRY_BEGIN // allocate control block and reset 240 _Resetp0(_Px, new _Ref_count<_Ux>(_Px)); 241 _CATCH_ALL // allocation failed, delete resource 242 delete _Px; 243 _RERAISE; 244 _CATCH_END 245 } 246 247 template<class _Ux, 248 class _Dx> 249 void _Resetp(_Ux *_Px, _Dx _Dt) 250 { // release, take ownership of _Px, deleter _Dt 251 _TRY_BEGIN // allocate control block and reset 252 _Resetp0(_Px, new _Ref_count_del<_Ux, _Dx>(_Px, _Dt)); 253 _CATCH_ALL // allocation failed, delete resource 254 _Dt(_Px); 255 _RERAISE; 256 _CATCH_END 257 } 258 259 //#if _HAS_CPP0X 260 template<class _Ux, 261 class _Dx, 262 class _Alloc> 263 void _Resetp(_Ux *_Px, _Dx _Dt, _Alloc _Ax) 264 { // release, take ownership of _Px, deleter _Dt, allocator _Ax 265 typedef _Ref_count_del_alloc<_Ux, _Dx, _Alloc> _Refd; 266 typename _Alloc::template rebind<_Refd>::other _Al = _Ax; 267 268 _TRY_BEGIN // allocate control block and reset 269 _Refd *_Ptr = _Al.allocate(1); 270 ::new (_Ptr) _Refd(_Px, _Dt, _Al); 271 _Resetp0(_Px, _Ptr); 272 _CATCH_ALL // allocation failed, delete resource 273 _Dt(_Px); 274 _RERAISE; 275 _CATCH_END 276 } 277 //#endif /* _HAS_CPP0X */ 278 279 public: 280 template<class _Ux> 281 void _Resetp0(_Ux *_Px, _Ref_count_base *_Rx) 282 { // release resource and take ownership of _Px 283 this->_Reset0(_Px, _Rx); 284 _Enable_shared(_Px, _Rx); 285 } 286 };
咱們能夠看到shared_ptr是繼承於_Ptr_base的,(同時weak_ptr也繼承與_Ptr_base)ide
那麼咱們先來看一下_Ptr_base裏有什麼東西函數
首先咱們能夠看到_Ptr_base裏面有兩個屬性oop
private: _Ty *_Ptr; _Ref_count_base *_Rep;
從shared_ptr咱們知道_Ptr_base是個模板,而_Ty是傳到_Ptr_base裏的模板參數,也就是指針的類型測試
因此咱們知道 _Ptr 保存的值就是真正的指針ui
可是 _Ref_count_base *_Rep 是什麼東西呢,很明顯就是引用計數。爲何要用指針呢,由於擁有相同_Ptr值的智能指針要擁有同一個引用計數,所以 _Rep 必須爲指針。咱們把引用計數類_Ref_count_base 放到後面去討論。this
咱們繼續看一下shared_ptr的源碼能夠發現shared_ptr沒有顯式調用_Ptr_base的構造函數,這意味着shared_ptr只調用_Ptr_base的默認構造函數,可是atom
shared_ptr的構造函數裏大量的調用了兩個函數 _Resetp 和 _Reset。spa
------------------------------------------------------------ _Ptr_base的構造函數 -------------------------------------------------------------------
咱們先看一下_Ptr_base的構造函數
_Ptr_base() : _Ptr(0), _Rep(0) { // construct } _Ptr_base(_Myt&& _Right) : _Ptr(0), _Rep(0) { // construct _Ptr_base object that takes resource from _Right _Assign_rv(_STD forward<_Myt>(_Right)); } template<class _Ty2> _Ptr_base(_Ptr_base<_Ty2>&& _Right) : _Ptr(_Right._Ptr), _Rep(_Right._Rep) { // construct _Ptr_base object that takes resource from _Right _Right._Ptr = 0; _Right._Rep = 0; }
_Ptr_base的默認構造函數是指針置位nullptr,這沒什麼好說的。剩下兩個是轉移構造函數,比較奇怪的是
template<class _Ty2> _Ptr_base(_Ptr_base<_Ty2>&& _Right)
接受以任意類型做爲模板參數的_Ptr_base?不懂,估計與shared_ptr向上轉型有關。
------------------------------------------------------------ _Ptr_base的_Resetp函數 -------------------------------------------------------------
而後咱們看一下_Resetp函數
template<class _Ux> void _Resetp(_Ux *_Px) { // release, take ownership of _Px _TRY_BEGIN // allocate control block and reset _Resetp0(_Px, new _Ref_count<_Ux>(_Px)); _CATCH_ALL // allocation failed, delete resource delete _Px; _RERAISE; _CATCH_END } template<class _Ux, class _Dx> void _Resetp(_Ux *_Px, _Dx _Dt) { // release, take ownership of _Px, deleter _Dt _TRY_BEGIN // allocate control block and reset _Resetp0(_Px, new _Ref_count_del<_Ux, _Dx>(_Px, _Dt)); _CATCH_ALL // allocation failed, delete resource _Dt(_Px); _RERAISE; _CATCH_END } //#if _HAS_CPP0X template<class _Ux, class _Dx, class _Alloc> void _Resetp(_Ux *_Px, _Dx _Dt, _Alloc _Ax) { // release, take ownership of _Px, deleter _Dt, allocator _Ax typedef _Ref_count_del_alloc<_Ux, _Dx, _Alloc> _Refd; typename _Alloc::template rebind<_Refd>::other _Al = _Ax; _TRY_BEGIN // allocate control block and reset _Refd *_Ptr = _Al.allocate(1); ::new (_Ptr) _Refd(_Px, _Dt, _Al); _Resetp0(_Px, _Ptr); _CATCH_ALL // allocation failed, delete resource _Dt(_Px); _RERAISE; _CATCH_END }
_Resetp函數有三個重載,實際上就是 是否帶析構器_Dx 和 是否帶構造器_Alloc, 這兩個參數都用於引用計數,咱們繼續留到後面討論。
_Resetp函數的三個重載裏又都調用了_Resetp0
template<class _Ux> void _Resetp0(_Ux *_Px, _Ref_count_base *_Rx) { // release resource and take ownership of _Px this->_Reset0(_Px, _Rx); _Enable_shared(_Px, _Rx); }
這裏又調用了父類_Ptr_base的_Reset0 和另外一個函數_Enable_shared
先看一下_Reset0
void _Reset0(_Ty *_Other_ptr, _Ref_count_base *_Other_rep) { // release resource and take new resource if (_Rep != 0) _Rep->_Decref(); _Rep = _Other_rep; _Ptr = _Other_ptr; }
就是檢查一下當前_Ptr_base引用計數指針是否爲空,非空就釋放一個引用計數,而後更新指針值和引用計數值
(爲何叫_Reset0? 0表示最基本的Reset?)
再看一下_Enable_shared
template<class _Ty> inline void _Enable_shared(_Ty *_Ptr, _Ref_count_base *_Refptr, typename _Ty::_EStype * = 0) { // reset internal weak pointer if (_Ptr) _Do_enable(_Ptr, (enable_shared_from_this<typename _Ty::_EStype>*)_Ptr, _Refptr); } inline void _Enable_shared(const volatile void *, const volatile void *) { // not derived from enable_shared_from_this; do nothing }
這裏用了模板的最特化匹配
當_Ty有定義_EStype這個類型名的時候(也就是_Ty繼承於enable_shared_from_this<_Ty>的時候)會調用第一個函數。
這裏我簡單描述一下_Do_enable的做用:
由於_Ty繼承於enable_shared_from_this<typename _Ty::_EStype>(實際上_Ty::_EStype就是_Ty,有興趣的朋友能夠去看一下 enable_shared_from_this的源碼),enable_shared_from_this<typename _Ty::_EStype>內部保存着一個weak_ptr<_Ty>的弱指針,而_Do_enable的做用就是更新一下這個弱指針的值(使用過shared_ptr的朋友都應該知道enable_shared_from_this是用於共享this指針,而這個共享this指針的操做就是經過這個weak_ptr達到的)。
------------------------------------------------------------ shared_ptr的構造函數 -------------------------------------------------------------
接着咱們看一下shared_ptr的調用了_reset的構造函數
1 shared_ptr(const _Myt& _Other) _NOEXCEPT 2 { // construct shared_ptr object that owns same resource as _Other 3 this->_Reset(_Other); 4 } 5 6 template<class _Ty2> 7 shared_ptr(const shared_ptr<_Ty2>& _Other, 8 typename enable_if<is_convertible<_Ty2 *, _Ty *>::value, 9 void>::type ** = 0) _NOEXCEPT 10 { // construct shared_ptr object that owns same resource as _Other 11 this->_Reset(_Other); 12 } 13 14 template<class _Ty2> 15 explicit shared_ptr(const weak_ptr<_Ty2>& _Other, 16 bool _Throw = true) 17 { // construct shared_ptr object that owns resource *_Other 18 this->_Reset(_Other, _Throw); 19 } 20 21 template<class _Ty2> 22 shared_ptr(auto_ptr<_Ty2>&& _Other) 23 { // construct shared_ptr object that owns *_Other.get() 24 this->_Reset(_STD move(_Other)); 25 } 26 27 template<class _Ty2> 28 shared_ptr(const shared_ptr<_Ty2>& _Other, const _Static_tag& _Tag) 29 { // construct shared_ptr object for static_pointer_cast 30 this->_Reset(_Other, _Tag); 31 } 32 33 template<class _Ty2> 34 shared_ptr(const shared_ptr<_Ty2>& _Other, const _Const_tag& _Tag) 35 { // construct shared_ptr object for const_pointer_cast 36 this->_Reset(_Other, _Tag); 37 } 38 39 template<class _Ty2> 40 shared_ptr(const shared_ptr<_Ty2>& _Other, const _Dynamic_tag& _Tag) 41 { // construct shared_ptr object for dynamic_pointer_cast 42 this->_Reset(_Other, _Tag); 43 }
這裏又用到了模板的最特化匹配,注意L1 - L12
is_convertible<_Ty2 *, _Ty *>::value
是C++11提供的一個類型測試模板,用於測試_Ty2 * 與 _Ty *之間是否有合法轉換。當有的時候將調用函數L6 - L12,不然調用L1 - L4
這也是shared_ptr<_Ty>能夠向shared_ptr<_Ty的父類>向上轉型的祕密。
PS:注意shared_ptr還有一個轉移構造函數與上面提到的_Ptr_base的轉移構造函數相對應
1 template<class _Ty2> 2 shared_ptr(shared_ptr<_Ty2>&& _Right, 3 typename enable_if<is_convertible<_Ty2 *, _Ty *>::value, 4 void>::type ** = 0) _NOEXCEPT 5 : _Mybase(_STD forward<shared_ptr<_Ty2> >(_Right)) 6 { // construct shared_ptr object that takes resource from _Right 7 }
而後L27 - L43的三個構造函數分別用於static_cast、const_cast、dynamic_cast轉型。
轉型函數見
template<class _Ty1, class _Ty2> shared_ptr<_Ty1> static_pointer_cast(const shared_ptr<_Ty2>& _Other) _NOEXCEPT { // return shared_ptr object holding static_cast<_Ty1 *>(_Other.get()) return (shared_ptr<_Ty1>(_Other, _Static_tag())); } template<class _Ty1, class _Ty2> shared_ptr<_Ty1> const_pointer_cast(const shared_ptr<_Ty2>& _Other) _NOEXCEPT { // return shared_ptr object holding const_cast<_Ty1 *>(_Other.get()) return (shared_ptr<_Ty1>(_Other, _Const_tag())); } template<class _Ty1, class _Ty2> shared_ptr<_Ty1> dynamic_pointer_cast(const shared_ptr<_Ty2>& _Other) _NOEXCEPT { // return shared_ptr object holding dynamic_cast<_Ty1 *>(_Other.get()) return (shared_ptr<_Ty1>(_Other, _Dynamic_tag())); }
------------------------------------------------------------ _Ptr_base的_Reset函數 -------------------------------------------------------------
咱們最後咱們看一下_Ptr_base的_Reset函數
1 void _Reset() 2 { // release resource 3 _Reset(0, 0); 4 } 5 6 template<class _Ty2> 7 void _Reset(const _Ptr_base<_Ty2>& _Other) 8 { // release resource and take ownership of _Other._Ptr 9 _Reset(_Other._Ptr, _Other._Rep); 10 } 11 12 template<class _Ty2> 13 void _Reset(const _Ptr_base<_Ty2>& _Other, bool _Throw) 14 { // release resource and take ownership from weak_ptr _Other._Ptr 15 _Reset(_Other._Ptr, _Other._Rep, _Throw); 16 } 17 18 template<class _Ty2> 19 void _Reset(const _Ptr_base<_Ty2>& _Other, const _Static_tag&) 20 { // release resource and take ownership of _Other._Ptr 21 _Reset(static_cast<_Elem *>(_Other._Ptr), _Other._Rep); 22 } 23 24 template<class _Ty2> 25 void _Reset(const _Ptr_base<_Ty2>& _Other, const _Const_tag&) 26 { // release resource and take ownership of _Other._Ptr 27 _Reset(const_cast<_Elem *>(_Other._Ptr), _Other._Rep); 28 } 29 30 template<class _Ty2> 31 void _Reset(const _Ptr_base<_Ty2>& _Other, const _Dynamic_tag&) 32 { // release resource and take ownership of _Other._Ptr 33 _Elem *_Ptr = dynamic_cast<_Elem *>(_Other._Ptr); 34 if (_Ptr) 35 _Reset(_Ptr, _Other._Rep); 36 else 37 _Reset(); 38 } 39 40 template<class _Ty2> 41 void _Reset(auto_ptr<_Ty2>&& _Other) 42 { // release resource and take _Other.get() 43 _Ty2 *_Px = _Other.get(); 44 _Reset0(_Px, new _Ref_count<_Elem>(_Px)); 45 _Other.release(); 46 _Enable_shared(_Px, _Rep); 47 } 48 49 #if _HAS_CPP0X 50 template<class _Ty2> 51 void _Reset(_Ty *_Ptr, const _Ptr_base<_Ty2>& _Other) 52 { // release resource and alias _Ptr with _Other_rep 53 _Reset(_Ptr, _Other._Rep); 54 } 55 #endif /* _HAS_CPP0X */ 56 57 void _Reset(_Ty *_Other_ptr, _Ref_count_base *_Other_rep) 58 { // release resource and take _Other_ptr through _Other_rep 59 if (_Other_rep) 60 _Other_rep->_Incref(); 61 _Reset0(_Other_ptr, _Other_rep); 62 } 63 64 void _Reset(_Ty *_Other_ptr, _Ref_count_base *_Other_rep, bool _Throw) 65 { // take _Other_ptr through _Other_rep from weak_ptr if not expired 66 // otherwise, leave in default state if !_Throw, 67 // otherwise throw exception 68 if (_Other_rep && _Other_rep->_Incref_nz()) 69 _Reset0(_Other_ptr, _Other_rep); 70 else if (_Throw) 71 _THROW_NCEE(bad_weak_ptr, 0); 72 }
實際上也就是轉發一下到_Reset0函數
------------------------------------------------------------ _Ptr_base的_Resetw函數 ------------------------------------------------------------
除此以外,咱們還能夠發現_Ptr_base中還有幾個相似的函數_Resetw,這幾個函數是爲了被weak_ptr調用的,在這裏咱們不詳細說,但在下面討論_Ref_count_base 的時候會被說起。
1 void _Resetw() 2 { // release weak reference to resource 3 _Resetw((_Elem *)0, 0); 4 } 5 6 template<class _Ty2> 7 void _Resetw(const _Ptr_base<_Ty2>& _Other) 8 { // release weak reference to resource and take _Other._Ptr 9 _Resetw(_Other._Ptr, _Other._Rep); 10 } 11 12 template<class _Ty2> 13 void _Resetw(const _Ty2 *_Other_ptr, _Ref_count_base *_Other_rep) 14 { // point to _Other_ptr through _Other_rep 15 _Resetw(const_cast<_Ty2*>(_Other_ptr), _Other_rep); 16 } 17 18 template<class _Ty2> 19 void _Resetw(_Ty2 *_Other_ptr, _Ref_count_base *_Other_rep) 20 { // point to _Other_ptr through _Other_rep 21 if (_Other_rep) 22 _Other_rep->_Incwref(); 23 if (_Rep != 0) 24 _Rep->_Decwref(); 25 _Rep = _Other_rep; 26 _Ptr = _Other_ptr; 27 }
--------------------------------------------------------------- _Ref_count_base ---------------------------------------------------------------
_Ref_count_base有兩個虛函數,_Ref_count_base的幾個子類(帶析構器和帶構造器)只是override了這兩個函數,來產生不一樣的指針析構行爲和自身析構行爲。
virtual void _Destroy() = 0;
virtual void _Delete_this() = 0;
所以咱們只須要研究_Ref_count_base自己就好。
_Ref_count_base帶有兩個數據成員(指針數據成員在具體子類裏面)
_Atomic_counter_t _Uses;
_Atomic_counter_t _Weaks;
從名字能夠猜想出來 _Uses 是shared_ptr的引用計數, _Weaks 是weak_ptr的引用計數
爲何咱們須要 _Weaks 呢? 由於在_Uses 引用計數爲0(最後一個shared_ptr已經被析構)的時候咱們就應該析構掉真正的指針,但問題是這個引用計數對象自己也是一個指針,那麼這個引用計數也要在這時候被析構嗎?使用過shared_ptr的朋友會知道,shared_ptr 有一個與之緊密相連的類 weak_ptr 實際上由一個shared_ptr 產生的weak_ptr是共享同一個引用計數對象的(這樣子weak_ptr就能夠知道真正的指針是否被析構掉了)。若是因此 shared_ptr 都被析構掉了同時其引用計數對象,但析構掉了,但有這個 shared_ptr 產生的 weak_ptr 仍然存在那麼就可能致使 weak_ptr 訪問一個已經被析構的指針。 所以應該是全部的 shared_ptr 與其 產生的weak_ptr 都被析構掉了,其引用計數對象才被析構掉。
咱們能夠從下面的減小引用計數函數看出來。
PS: #define _MT_DECR _InterlockedIncrement(reinterpret_cast<volatile long *>(&x))
1 void _Decref() 2 { // decrement use count 3 if (_MT_DECR(_Ignored, _Uses) == 0) 4 { // destroy managed resource, decrement weak reference count 5 _Destroy(); 6 _Decwref(); 7 } 8 } 9 10 void _Decwref() 11 { // decrement weak reference count 12 if (_MT_DECR(_Ignored, _Weaks) == 0) 13 _Delete_this(); 14 }
與上面相對應的增長引用計數函數
PS: #define _MT_INCR(mtx, x)_InterlockedIncrement(reinterpret_cast<volatile long *>(&x))
1 void _Incref() 2 { // increment use count 3 _MT_INCR(_Ignored, _Uses); 4 } 5 6 void _Incwref() 7 { // increment weak reference count 8 _MT_INCR(_Ignored, _Weaks); 9 }
再補上 _Ref_count_base 的構造函數
1 _Ref_count_base() 2 { // construct 3 _Init_atomic_counter(_Uses, 1); 4 _Init_atomic_counter(_Weaks, 1); 5 }
咱們能夠看到 _Ref_count_base 構造函數中對 _Uses 與 _Weaks 初始化引用計數爲1,_Uses 爲0時析構指針, _Weaks 爲0時析構引用計數對象。
比較有趣的是咱們能夠從 weak_ptr 指針 lock 出一個 shared_ptr 指針的時候,會調用_Ref_count_base 類的函數 _Incref_nz,這個函數檢查引用計數對象的引用計數是否爲0,非零(未析構真正指針)的時候就能夠增長一個引用計數。這裏面爲了 Lock-Free 調用了函數 _InterlockedCompareExchange。
1 bool _Incref_nz() 2 { // increment use count if not zero, return true if successful 3 for (; ; ) 4 { // loop until state is known 5 #if defined(_M_IX86) || defined(_M_X64) || defined(_M_CEE_PURE) 6 _Atomic_integral_t _Count = 7 static_cast<volatile _Atomic_counter_t&>(_Uses); 8 9 if (_Count == 0) 10 return (false); 11 12 if (static_cast<_Atomic_integral_t>(_InterlockedCompareExchange( 13 reinterpret_cast<volatile long *>(&_Uses), 14 _Count + 1, _Count)) == _Count) 15 return (true); 16 #else /* defined(_M_IX86) || defined(_M_X64) || defined(_M_CEE_PURE) */ 17 _Atomic_integral_t _Count = 18 _Load_atomic_counter_explicit(_Uses, memory_order_relaxed); 19 20 if (_Count == 0) 21 return (false); 22 23 if (_Compare_increment_atomic_counter_explicit( 24 _Uses, _Count, memory_order_relaxed)) 25 return (true); 26 #endif /* defined(_M_IX86) || defined(_M_X64) || defined(_M_CEE_PURE) */ 27 } 28 }
由於 _Ref_count_base 裏面的引用計數增長/減小都是Lock-Free的,所以對shared_ptr的引用計數是多線程安全的。
--------------------------------------------------------------- shared_ptr的線程安全---------------------------------------------------------------
多個線程同時對同一個shared_ptr的寫操做是不安全的,由於其swap函數
1 void swap(_Myt& _Other) _NOEXCEPT 2 { // swap pointers 3 this->_Swap(_Other); 4 }
調用了一個非線程安全函數_Ptr_base的_Swap
1 void _Swap(_Ptr_base& _Right) 2 { // swap pointers 3 _STD swap(_Rep, _Right._Rep); 4 _STD swap(_Ptr, _Right._Ptr); 5 }
可是多個線程同時對共享引用計數的不一樣shared_ptr的寫操做是安全的,由於對於真正的指針,shared_ptr只對其進行簡單的讀寫不修改其指向的對象的內部狀態,並且同一時刻只有一個線程對某個shared_ptr真正的指針進行讀寫,所以線程安全的。對於引用計數對象,雖然修改了其內部狀態,但自己這種修改動做是線程安全的。因此咱們能夠推論多個線程同時對共享引用計數的不一樣shared_ptr的寫操做也是安全的。
boost庫對shared_ptr的描述也證實了這一點。
shared_ptr objects offer the same level of thread safety as builtin types.
A shared_ptr instance can be "read" (accessed using only const operations) simultaneously by multiple threads.
Different shared_ptr instances can be "written to" (accessed using mutable operations such as operator= or reset) simultaneosly
by multiple threads (even when these instances are copies, and share the same reference count underneath.)
Any other simultaneous accesses result in undefined behavior.
翻譯爲中文以下:
shared_ptr 對象提供與內建類型同樣的線程安全級別。一個 shared_ptr 實例能夠同時被多個線程「讀」(僅使用不變操做進行訪問)。 不一樣的 shared_ptr 實例能夠同時被多個線程「寫入」(使用相似 operator= 或 reset 這樣的可變操做進行訪問)(即便這些實 例是拷貝,並且共享下層的引用計數)。
任何其它的同時訪問的結果會致使未定義行爲。」