当前位置:   article > 正文

C++ 智能指针(shared_ptr/weak_ptr)源码分析_c++ 智能指针源码解析

c++ 智能指针源码解析

C++11目前已经引入了unique_ptr, shared_ptr, weak_ptr等智能指针以及相关的模板类enable_shared_from_this等。shared_ptr实现了C++中的RAII机制,它不仅仅具有一般指针(build-in/raw)的特性,更重要的是它可以自动管理用户在堆上创建的对象的生命周期,让用户不用为内存回收操心,避免内存泄漏。一般的智能指针都定义为一个模板类,它的类型由被管理的对象类型初始化,内部包含了指向该对象的指针以及指向辅助生命周期管理的管理对象的指针。

 

C++11中unique_ptr, shared_ptr, weak_ptr的特点如下:

  • unique_ptr独享被管理对象,同一时刻只能有一个unique_ptr拥有对象的所有权,当其被赋值时对象的所有权也发生转移,当其被销毁时被管理对象也自动被销毁
  • shared_ptr共享被管理对象,同一时刻可以有多个shared_ptr拥有对象的所有权,当最后一个shared_ptr对象销毁时,被管理对象自动销毁
  • weak_ptr不拥有对象的所有权,但是它可以判断对象是否存在和返回指向对象的shared_ptr类型指针;它的用途之一是解决多个对象内部含有shared_ptr循环指向,导致对象无法释放的问题

那么C++中是怎么实现这些特性的呢,我们可以在gcc的源码目录(gcc-6.1.0\gcc-6.1.0\libstdc++-v3\include\tr1)中找到智能指针的一种实现,通过分析其源码找到答案(其它boost::shared_ptr等的实现也是类似的)。gcc中相关智能指针的实现源码如下:

 

  1. // <tr1/shared_ptr.h> -*- C++ -*-
  2. // Copyright (C) 2007-2016 Free Software Foundation, Inc.
  3. //
  4. // This file is part of the GNU ISO C++ Library. This library is free
  5. // software; you can redistribute it and/or modify it under the
  6. // terms of the GNU General Public License as published by the
  7. // Free Software Foundation; either version 3, or (at your option)
  8. // any later version.
  9. // This library is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU General Public License for more details.
  13. // Under Section 7 of GPL version 3, you are granted additional
  14. // permissions described in the GCC Runtime Library Exception, version
  15. // 3.1, as published by the Free Software Foundation.
  16. // You should have received a copy of the GNU General Public License and
  17. // a copy of the GCC Runtime Library Exception along with this program;
  18. // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
  19. // <http://www.gnu.org/licenses/>.
  20. // shared_count.hpp
  21. // Copyright (c) 2001, 2002, 2003 Peter Dimov and Multi Media Ltd.
  22. // shared_ptr.hpp
  23. // Copyright (C) 1998, 1999 Greg Colvin and Beman Dawes.
  24. // Copyright (C) 2001, 2002, 2003 Peter Dimov
  25. // weak_ptr.hpp
  26. // Copyright (C) 2001, 2002, 2003 Peter Dimov
  27. // enable_shared_from_this.hpp
  28. // Copyright (C) 2002 Peter Dimov
  29. // Distributed under the Boost Software License, Version 1.0. (See
  30. // accompanying file LICENSE_1_0.txt or copy at
  31. // http://www.boost.org/LICENSE_1_0.txt)
  32. // GCC Note: based on version 1.32.0 of the Boost library.
  33. /** @file tr1/shared_ptr.h
  34. * This is an internal header file, included by other library headers.
  35. * Do not attempt to use it directly. @headername{tr1/memory}
  36. */
  37. #ifndef _TR1_SHARED_PTR_H
  38. #define _TR1_SHARED_PTR_H 1
  39. namespace std _GLIBCXX_VISIBILITY(default)
  40. {
  41. namespace tr1
  42. {
  43. _GLIBCXX_BEGIN_NAMESPACE_VERSION
  44. /**
  45. * @brief Exception possibly thrown by @c shared_ptr.
  46. * @ingroup exceptions
  47. */
  48. class bad_weak_ptr : public std::exception
  49. {
  50. public:
  51. virtual char const*
  52. what() const throw()
  53. { return "tr1::bad_weak_ptr"; }
  54. };
  55. // Substitute for bad_weak_ptr object in the case of -fno-exceptions.
  56. inline void
  57. __throw_bad_weak_ptr()
  58. { _GLIBCXX_THROW_OR_ABORT(bad_weak_ptr()); }
  59. using __gnu_cxx::_Lock_policy;
  60. using __gnu_cxx::__default_lock_policy;
  61. using __gnu_cxx::_S_single;
  62. using __gnu_cxx::_S_mutex;
  63. using __gnu_cxx::_S_atomic;
  64. // Empty helper class except when the template argument is _S_mutex.
  65. template<_Lock_policy _Lp>
  66. class _Mutex_base
  67. {
  68. protected:
  69. // The atomic policy uses fully-fenced builtins, single doesn't care.
  70. enum { _S_need_barriers = 0 };
  71. };
  72. template<>
  73. class _Mutex_base<_S_mutex>
  74. : public __gnu_cxx::__mutex
  75. {
  76. protected:
  77. // This policy is used when atomic builtins are not available.
  78. // The replacement atomic operations might not have the necessary
  79. // memory barriers.
  80. enum { _S_need_barriers = 1 };
  81. };
  82. template<_Lock_policy _Lp = __default_lock_policy>
  83. class _Sp_counted_base
  84. : public _Mutex_base<_Lp>
  85. {
  86. public:
  87. _Sp_counted_base()
  88. : _M_use_count(1), _M_weak_count(1) { }
  89. virtual
  90. ~_Sp_counted_base() // nothrow
  91. { }
  92. // Called when _M_use_count drops to zero, to release the resources
  93. // managed by *this.
  94. virtual void
  95. _M_dispose() = 0; // nothrow
  96. // Called when _M_weak_count drops to zero.
  97. virtual void
  98. _M_destroy() // nothrow
  99. { delete this; }
  100. virtual void*
  101. _M_get_deleter(const std::type_info&) = 0;
  102. void
  103. _M_add_ref_copy()
  104. { __gnu_cxx::__atomic_add_dispatch(&_M_use_count, 1); }
  105. void
  106. _M_add_ref_lock();
  107. void
  108. _M_release() // nothrow
  109. {
  110. // Be race-detector-friendly. For more info see bits/c++config.
  111. _GLIBCXX_SYNCHRONIZATION_HAPPENS_BEFORE(&_M_use_count);
  112. if (__gnu_cxx::__exchange_and_add_dispatch(&_M_use_count, -1) == 1)
  113. {
  114. _GLIBCXX_SYNCHRONIZATION_HAPPENS_AFTER(&_M_use_count);
  115. _M_dispose();
  116. // There must be a memory barrier between dispose() and destroy()
  117. // to ensure that the effects of dispose() are observed in the
  118. // thread that runs destroy().
  119. // See http://gcc.gnu.org/ml/libstdc++/2005-11/msg00136.html
  120. if (_Mutex_base<_Lp>::_S_need_barriers)
  121. {
  122. __atomic_thread_fence (__ATOMIC_ACQ_REL);
  123. }
  124. // Be race-detector-friendly. For more info see bits/c++config.
  125. _GLIBCXX_SYNCHRONIZATION_HAPPENS_BEFORE(&_M_weak_count);
  126. if (__gnu_cxx::__exchange_and_add_dispatch(&_M_weak_count,
  127. -1) == 1)
  128. {
  129. _GLIBCXX_SYNCHRONIZATION_HAPPENS_AFTER(&_M_weak_count);
  130. _M_destroy();
  131. }
  132. }
  133. }
  134. void
  135. _M_weak_add_ref() // nothrow
  136. { __gnu_cxx::__atomic_add_dispatch(&_M_weak_count, 1); }
  137. void
  138. _M_weak_release() // nothrow
  139. {
  140. // Be race-detector-friendly. For more info see bits/c++config.
  141. _GLIBCXX_SYNCHRONIZATION_HAPPENS_BEFORE(&_M_weak_count);
  142. if (__gnu_cxx::__exchange_and_add_dispatch(&_M_weak_count, -1) == 1)
  143. {
  144. _GLIBCXX_SYNCHRONIZATION_HAPPENS_AFTER(&_M_weak_count);
  145. if (_Mutex_base<_Lp>::_S_need_barriers)
  146. {
  147. // See _M_release(),
  148. // destroy() must observe results of dispose()
  149. __atomic_thread_fence (__ATOMIC_ACQ_REL);
  150. }
  151. _M_destroy();
  152. }
  153. }
  154. long
  155. _M_get_use_count() const // nothrow
  156. {
  157. // No memory barrier is used here so there is no synchronization
  158. // with other threads.
  159. return const_cast<const volatile _Atomic_word&>(_M_use_count);
  160. }
  161. private:
  162. _Sp_counted_base(_Sp_counted_base const&);
  163. _Sp_counted_base& operator=(_Sp_counted_base const&);
  164. _Atomic_word _M_use_count; // #shared
  165. _Atomic_word _M_weak_count; // #weak + (#shared != 0)
  166. };
  167. template<>
  168. inline void
  169. _Sp_counted_base<_S_single>::
  170. _M_add_ref_lock()
  171. {
  172. if (__gnu_cxx::__exchange_and_add_dispatch(&_M_use_count, 1) == 0)
  173. {
  174. _M_use_count = 0;
  175. __throw_bad_weak_ptr();
  176. }
  177. }
  178. template<>
  179. inline void
  180. _Sp_counted_base<_S_mutex>::
  181. _M_add_ref_lock()
  182. {
  183. __gnu_cxx::__scoped_lock sentry(*this);
  184. if (__gnu_cxx::__exchange_and_add_dispatch(&_M_use_count, 1) == 0)
  185. {
  186. _M_use_count = 0;
  187. __throw_bad_weak_ptr();
  188. }
  189. }
  190. template<>
  191. inline void
  192. _Sp_counted_base<_S_atomic>::
  193. _M_add_ref_lock()
  194. {
  195. // Perform lock-free add-if-not-zero operation.
  196. _Atomic_word __count = _M_use_count;
  197. do
  198. {
  199. if (__count == 0)
  200. __throw_bad_weak_ptr();
  201. // Replace the current counter value with the old value + 1, as
  202. // long as it's not changed meanwhile.
  203. }
  204. while (!__atomic_compare_exchange_n(&_M_use_count, &__count, __count + 1,
  205. true, __ATOMIC_ACQ_REL,
  206. __ATOMIC_RELAXED));
  207. }
  208. template<typename _Ptr, typename _Deleter, _Lock_policy _Lp>
  209. class _Sp_counted_base_impl
  210. : public _Sp_counted_base<_Lp>
  211. {
  212. public:
  213. // Precondition: __d(__p) must not throw.
  214. _Sp_counted_base_impl(_Ptr __p, _Deleter __d)
  215. : _M_ptr(__p), _M_del(__d) { }
  216. virtual void
  217. _M_dispose() // nothrow
  218. { _M_del(_M_ptr); }
  219. virtual void*
  220. _M_get_deleter(const std::type_info& __ti)
  221. {
  222. #if __cpp_rtti
  223. return __ti == typeid(_Deleter) ? &_M_del : 0;
  224. #else
  225. return 0;
  226. #endif
  227. }
  228. private:
  229. _Sp_counted_base_impl(const _Sp_counted_base_impl&);
  230. _Sp_counted_base_impl& operator=(const _Sp_counted_base_impl&);
  231. _Ptr _M_ptr; // copy constructor must not throw
  232. _Deleter _M_del; // copy constructor must not throw
  233. };
  234. template<_Lock_policy _Lp = __default_lock_policy>
  235. class __weak_count;
  236. template<typename _Tp>
  237. struct _Sp_deleter
  238. {
  239. typedef void result_type;
  240. typedef _Tp* argument_type;
  241. void operator()(_Tp* __p) const { delete __p; }
  242. };
  243. template<_Lock_policy _Lp = __default_lock_policy>
  244. class __shared_count
  245. {
  246. public:
  247. __shared_count()
  248. : _M_pi(0) // nothrow
  249. { }
  250. template<typename _Ptr>
  251. __shared_count(_Ptr __p) : _M_pi(0)
  252. {
  253. __try
  254. {
  255. typedef typename std::tr1::remove_pointer<_Ptr>::type _Tp;
  256. _M_pi = new _Sp_counted_base_impl<_Ptr, _Sp_deleter<_Tp>, _Lp>(
  257. __p, _Sp_deleter<_Tp>());
  258. }
  259. __catch(...)
  260. {
  261. delete __p;
  262. __throw_exception_again;
  263. }
  264. }
  265. template<typename _Ptr, typename _Deleter>
  266. __shared_count(_Ptr __p, _Deleter __d) : _M_pi(0)
  267. {
  268. __try
  269. {
  270. _M_pi = new _Sp_counted_base_impl<_Ptr, _Deleter, _Lp>(__p, __d);
  271. }
  272. __catch(...)
  273. {
  274. __d(__p); // Call _Deleter on __p.
  275. __throw_exception_again;
  276. }
  277. }
  278. // Special case for auto_ptr<_Tp> to provide the strong guarantee.
  279. template<typename _Tp>
  280. explicit
  281. __shared_count(std::auto_ptr<_Tp>& __r)
  282. : _M_pi(new _Sp_counted_base_impl<_Tp*,
  283. _Sp_deleter<_Tp>, _Lp >(__r.get(), _Sp_deleter<_Tp>()))
  284. { __r.release(); }
  285. // Throw bad_weak_ptr when __r._M_get_use_count() == 0.
  286. explicit
  287. __shared_count(const __weak_count<_Lp>& __r);
  288. ~__shared_count() // nothrow
  289. {
  290. if (_M_pi != 0)
  291. _M_pi->_M_release();
  292. }
  293. __shared_count(const __shared_count& __r)
  294. : _M_pi(__r._M_pi) // nothrow
  295. {
  296. if (_M_pi != 0)
  297. _M_pi->_M_add_ref_copy();
  298. }
  299. __shared_count&
  300. operator=(const __shared_count& __r) // nothrow
  301. {
  302. _Sp_counted_base<_Lp>* __tmp = __r._M_pi;
  303. if (__tmp != _M_pi)
  304. {
  305. if (__tmp != 0)
  306. __tmp->_M_add_ref_copy();
  307. if (_M_pi != 0)
  308. _M_pi->_M_release();
  309. _M_pi = __tmp;
  310. }
  311. return *this;
  312. }
  313. void
  314. _M_swap(__shared_count& __r) // nothrow
  315. {
  316. _Sp_counted_base<_Lp>* __tmp = __r._M_pi;
  317. __r._M_pi = _M_pi;
  318. _M_pi = __tmp;
  319. }
  320. long
  321. _M_get_use_count() const // nothrow
  322. { return _M_pi != 0 ? _M_pi->_M_get_use_count() : 0; }
  323. bool
  324. _M_unique() const // nothrow
  325. { return this->_M_get_use_count() == 1; }
  326. friend inline bool
  327. operator==(const __shared_count& __a, const __shared_count& __b)
  328. { return __a._M_pi == __b._M_pi; }
  329. friend inline bool
  330. operator<(const __shared_count& __a, const __shared_count& __b)
  331. { return std::less<_Sp_counted_base<_Lp>*>()(__a._M_pi, __b._M_pi); }
  332. void*
  333. _M_get_deleter(const std::type_info& __ti) const
  334. { return _M_pi ? _M_pi->_M_get_deleter(__ti) : 0; }
  335. private:
  336. friend class __weak_count<_Lp>;
  337. _Sp_counted_base<_Lp>* _M_pi;
  338. };
  339. template<_Lock_policy _Lp>
  340. class __weak_count
  341. {
  342. public:
  343. __weak_count()
  344. : _M_pi(0) // nothrow
  345. { }
  346. __weak_count(const __shared_count<_Lp>& __r)
  347. : _M_pi(__r._M_pi) // nothrow
  348. {
  349. if (_M_pi != 0)
  350. _M_pi->_M_weak_add_ref();
  351. }
  352. __weak_count(const __weak_count<_Lp>& __r)
  353. : _M_pi(__r._M_pi) // nothrow
  354. {
  355. if (_M_pi != 0)
  356. _M_pi->_M_weak_add_ref();
  357. }
  358. ~__weak_count() // nothrow
  359. {
  360. if (_M_pi != 0)
  361. _M_pi->_M_weak_release();
  362. }
  363. __weak_count<_Lp>&
  364. operator=(const __shared_count<_Lp>& __r) // nothrow
  365. {
  366. _Sp_counted_base<_Lp>* __tmp = __r._M_pi;
  367. if (__tmp != 0)
  368. __tmp->_M_weak_add_ref();
  369. if (_M_pi != 0)
  370. _M_pi->_M_weak_release();
  371. _M_pi = __tmp;
  372. return *this;
  373. }
  374. __weak_count<_Lp>&
  375. operator=(const __weak_count<_Lp>& __r) // nothrow
  376. {
  377. _Sp_counted_base<_Lp>* __tmp = __r._M_pi;
  378. if (__tmp != 0)
  379. __tmp->_M_weak_add_ref();
  380. if (_M_pi != 0)
  381. _M_pi->_M_weak_release();
  382. _M_pi = __tmp;
  383. return *this;
  384. }
  385. void
  386. _M_swap(__weak_count<_Lp>& __r) // nothrow
  387. {
  388. _Sp_counted_base<_Lp>* __tmp = __r._M_pi;
  389. __r._M_pi = _M_pi;
  390. _M_pi = __tmp;
  391. }
  392. long
  393. _M_get_use_count() const // nothrow
  394. { return _M_pi != 0 ? _M_pi->_M_get_use_count() : 0; }
  395. friend inline bool
  396. operator==(const __weak_count<_Lp>& __a, const __weak_count<_Lp>& __b)
  397. { return __a._M_pi == __b._M_pi; }
  398. friend inline bool
  399. operator<(const __weak_count<_Lp>& __a, const __weak_count<_Lp>& __b)
  400. { return std::less<_Sp_counted_base<_Lp>*>()(__a._M_pi, __b._M_pi); }
  401. private:
  402. friend class __shared_count<_Lp>;
  403. _Sp_counted_base<_Lp>* _M_pi;
  404. };
  405. // now that __weak_count is defined we can define this constructor:
  406. template<_Lock_policy _Lp>
  407. inline
  408. __shared_count<_Lp>::
  409. __shared_count(const __weak_count<_Lp>& __r)
  410. : _M_pi(__r._M_pi)
  411. {
  412. if (_M_pi != 0)
  413. _M_pi->_M_add_ref_lock();
  414. else
  415. __throw_bad_weak_ptr();
  416. }
  417. // Forward declarations.
  418. template<typename _Tp, _Lock_policy _Lp = __default_lock_policy>
  419. class __shared_ptr;
  420. template<typename _Tp, _Lock_policy _Lp = __default_lock_policy>
  421. class __weak_ptr;
  422. template<typename _Tp, _Lock_policy _Lp = __default_lock_policy>
  423. class __enable_shared_from_this;
  424. template<typename _Tp>
  425. class shared_ptr;
  426. template<typename _Tp>
  427. class weak_ptr;
  428. template<typename _Tp>
  429. class enable_shared_from_this;
  430. // Support for enable_shared_from_this.
  431. // Friend of __enable_shared_from_this.
  432. template<_Lock_policy _Lp, typename _Tp1, typename _Tp2>
  433. void
  434. __enable_shared_from_this_helper(const __shared_count<_Lp>&,
  435. const __enable_shared_from_this<_Tp1,
  436. _Lp>*, const _Tp2*);
  437. // Friend of enable_shared_from_this.
  438. template<typename _Tp1, typename _Tp2>
  439. void
  440. __enable_shared_from_this_helper(const __shared_count<>&,
  441. const enable_shared_from_this<_Tp1>*,
  442. const _Tp2*);
  443. template<_Lock_policy _Lp>
  444. inline void
  445. __enable_shared_from_this_helper(const __shared_count<_Lp>&, ...)
  446. { }
  447. struct __static_cast_tag { };
  448. struct __const_cast_tag { };
  449. struct __dynamic_cast_tag { };
  450. // A smart pointer with reference-counted copy semantics. The
  451. // object pointed to is deleted when the last shared_ptr pointing to
  452. // it is destroyed or reset.
  453. template<typename _Tp, _Lock_policy _Lp>
  454. class __shared_ptr
  455. {
  456. public:
  457. typedef _Tp element_type;
  458. __shared_ptr()
  459. : _M_ptr(0), _M_refcount() // never throws
  460. { }
  461. template<typename _Tp1>
  462. explicit
  463. __shared_ptr(_Tp1* __p)
  464. : _M_ptr(__p), _M_refcount(__p)
  465. {
  466. __glibcxx_function_requires(_ConvertibleConcept<_Tp1*, _Tp*>)
  467. typedef int _IsComplete[sizeof(_Tp1)];
  468. __enable_shared_from_this_helper(_M_refcount, __p, __p);
  469. }
  470. template<typename _Tp1, typename _Deleter>
  471. __shared_ptr(_Tp1* __p, _Deleter __d)
  472. : _M_ptr(__p), _M_refcount(__p, __d)
  473. {
  474. __glibcxx_function_requires(_ConvertibleConcept<_Tp1*, _Tp*>)
  475. // TODO requires _Deleter CopyConstructible and __d(__p) well-formed
  476. __enable_shared_from_this_helper(_M_refcount, __p, __p);
  477. }
  478. // generated copy constructor, assignment, destructor are fine.
  479. template<typename _Tp1>
  480. __shared_ptr(const __shared_ptr<_Tp1, _Lp>& __r)
  481. : _M_ptr(__r._M_ptr), _M_refcount(__r._M_refcount) // never throws
  482. { __glibcxx_function_requires(_ConvertibleConcept<_Tp1*, _Tp*>) }
  483. template<typename _Tp1>
  484. explicit
  485. __shared_ptr(const __weak_ptr<_Tp1, _Lp>& __r)
  486. : _M_refcount(__r._M_refcount) // may throw
  487. {
  488. __glibcxx_function_requires(_ConvertibleConcept<_Tp1*, _Tp*>)
  489. // It is now safe to copy __r._M_ptr, as _M_refcount(__r._M_refcount)
  490. // did not throw.
  491. _M_ptr = __r._M_ptr;
  492. }
  493. #if (__cplusplus < 201103L) || _GLIBCXX_USE_DEPRECATED
  494. // Postcondition: use_count() == 1 and __r.get() == 0
  495. template<typename _Tp1>
  496. explicit
  497. __shared_ptr(std::auto_ptr<_Tp1>& __r)
  498. : _M_ptr(__r.get()), _M_refcount()
  499. { // TODO requries delete __r.release() well-formed
  500. __glibcxx_function_requires(_ConvertibleConcept<_Tp1*, _Tp*>)
  501. typedef int _IsComplete[sizeof(_Tp1)];
  502. _Tp1* __tmp = __r.get();
  503. _M_refcount = __shared_count<_Lp>(__r);
  504. __enable_shared_from_this_helper(_M_refcount, __tmp, __tmp);
  505. }
  506. #endif
  507. template<typename _Tp1>
  508. __shared_ptr(const __shared_ptr<_Tp1, _Lp>& __r, __static_cast_tag)
  509. : _M_ptr(static_cast<element_type*>(__r._M_ptr)),
  510. _M_refcount(__r._M_refcount)
  511. { }
  512. template<typename _Tp1>
  513. __shared_ptr(const __shared_ptr<_Tp1, _Lp>& __r, __const_cast_tag)
  514. : _M_ptr(const_cast<element_type*>(__r._M_ptr)),
  515. _M_refcount(__r._M_refcount)
  516. { }
  517. template<typename _Tp1>
  518. __shared_ptr(const __shared_ptr<_Tp1, _Lp>& __r, __dynamic_cast_tag)
  519. : _M_ptr(dynamic_cast<element_type*>(__r._M_ptr)),
  520. _M_refcount(__r._M_refcount)
  521. {
  522. if (_M_ptr == 0) // need to allocate new counter -- the cast failed
  523. _M_refcount = __shared_count<_Lp>();
  524. }
  525. template<typename _Tp1>
  526. __shared_ptr&
  527. operator=(const __shared_ptr<_Tp1, _Lp>& __r) // never throws
  528. {
  529. _M_ptr = __r._M_ptr;
  530. _M_refcount = __r._M_refcount; // __shared_count::op= doesn't throw
  531. return *this;
  532. }
  533. #if (__cplusplus < 201103L) || _GLIBCXX_USE_DEPRECATED
  534. template<typename _Tp1>
  535. __shared_ptr&
  536. operator=(std::auto_ptr<_Tp1>& __r)
  537. {
  538. __shared_ptr(__r).swap(*this);
  539. return *this;
  540. }
  541. #endif
  542. void
  543. reset() // never throws
  544. { __shared_ptr().swap(*this); }
  545. template<typename _Tp1>
  546. void
  547. reset(_Tp1* __p) // _Tp1 must be complete.
  548. {
  549. // Catch self-reset errors.
  550. _GLIBCXX_DEBUG_ASSERT(__p == 0 || __p != _M_ptr);
  551. __shared_ptr(__p).swap(*this);
  552. }
  553. template<typename _Tp1, typename _Deleter>
  554. void
  555. reset(_Tp1* __p, _Deleter __d)
  556. { __shared_ptr(__p, __d).swap(*this); }
  557. // Allow class instantiation when _Tp is [cv-qual] void.
  558. typename std::tr1::add_reference<_Tp>::type
  559. operator*() const // never throws
  560. {
  561. _GLIBCXX_DEBUG_ASSERT(_M_ptr != 0);
  562. return *_M_ptr;
  563. }
  564. _Tp*
  565. operator->() const // never throws
  566. {
  567. _GLIBCXX_DEBUG_ASSERT(_M_ptr != 0);
  568. return _M_ptr;
  569. }
  570. _Tp*
  571. get() const // never throws
  572. { return _M_ptr; }
  573. // Implicit conversion to "bool"
  574. private:
  575. typedef _Tp* __shared_ptr::*__unspecified_bool_type;
  576. public:
  577. operator __unspecified_bool_type() const // never throws
  578. { return _M_ptr == 0 ? 0 : &__shared_ptr::_M_ptr; }
  579. bool
  580. unique() const // never throws
  581. { return _M_refcount._M_unique(); }
  582. long
  583. use_count() const // never throws
  584. { return _M_refcount._M_get_use_count(); }
  585. void
  586. swap(__shared_ptr<_Tp, _Lp>& __other) // never throws
  587. {
  588. std::swap(_M_ptr, __other._M_ptr);
  589. _M_refcount._M_swap(__other._M_refcount);
  590. }
  591. private:
  592. void*
  593. _M_get_deleter(const std::type_info& __ti) const
  594. { return _M_refcount._M_get_deleter(__ti); }
  595. template<typename _Tp1, _Lock_policy _Lp1>
  596. bool
  597. _M_less(const __shared_ptr<_Tp1, _Lp1>& __rhs) const
  598. { return _M_refcount < __rhs._M_refcount; }
  599. template<typename _Tp1, _Lock_policy _Lp1> friend class __shared_ptr;
  600. template<typename _Tp1, _Lock_policy _Lp1> friend class __weak_ptr;
  601. template<typename _Del, typename _Tp1, _Lock_policy _Lp1>
  602. friend _Del* get_deleter(const __shared_ptr<_Tp1, _Lp1>&);
  603. // Friends injected into enclosing namespace and found by ADL:
  604. template<typename _Tp1>
  605. friend inline bool
  606. operator==(const __shared_ptr& __a, const __shared_ptr<_Tp1, _Lp>& __b)
  607. { return __a.get() == __b.get(); }
  608. template<typename _Tp1>
  609. friend inline bool
  610. operator!=(const __shared_ptr& __a, const __shared_ptr<_Tp1, _Lp>& __b)
  611. { return __a.get() != __b.get(); }
  612. template<typename _Tp1>
  613. friend inline bool
  614. operator<(const __shared_ptr& __a, const __shared_ptr<_Tp1, _Lp>& __b)
  615. { return __a._M_less(__b); }
  616. _Tp* _M_ptr; // Contained pointer.
  617. __shared_count<_Lp> _M_refcount; // Reference counter.
  618. };
  619. // 2.2.3.8 shared_ptr specialized algorithms.
  620. template<typename _Tp, _Lock_policy _Lp>
  621. inline void
  622. swap(__shared_ptr<_Tp, _Lp>& __a, __shared_ptr<_Tp, _Lp>& __b)
  623. { __a.swap(__b); }
  624. // 2.2.3.9 shared_ptr casts
  625. /* The seemingly equivalent
  626. * shared_ptr<_Tp, _Lp>(static_cast<_Tp*>(__r.get()))
  627. * will eventually result in undefined behaviour,
  628. * attempting to delete the same object twice.
  629. */
  630. template<typename _Tp, typename _Tp1, _Lock_policy _Lp>
  631. inline __shared_ptr<_Tp, _Lp>
  632. static_pointer_cast(const __shared_ptr<_Tp1, _Lp>& __r)
  633. { return __shared_ptr<_Tp, _Lp>(__r, __static_cast_tag()); }
  634. /* The seemingly equivalent
  635. * shared_ptr<_Tp, _Lp>(const_cast<_Tp*>(__r.get()))
  636. * will eventually result in undefined behaviour,
  637. * attempting to delete the same object twice.
  638. */
  639. template<typename _Tp, typename _Tp1, _Lock_policy _Lp>
  640. inline __shared_ptr<_Tp, _Lp>
  641. const_pointer_cast(const __shared_ptr<_Tp1, _Lp>& __r)
  642. { return __shared_ptr<_Tp, _Lp>(__r, __const_cast_tag()); }
  643. /* The seemingly equivalent
  644. * shared_ptr<_Tp, _Lp>(dynamic_cast<_Tp*>(__r.get()))
  645. * will eventually result in undefined behaviour,
  646. * attempting to delete the same object twice.
  647. */
  648. template<typename _Tp, typename _Tp1, _Lock_policy _Lp>
  649. inline __shared_ptr<_Tp, _Lp>
  650. dynamic_pointer_cast(const __shared_ptr<_Tp1, _Lp>& __r)
  651. { return __shared_ptr<_Tp, _Lp>(__r, __dynamic_cast_tag()); }
  652. // 2.2.3.7 shared_ptr I/O
  653. template<typename _Ch, typename _Tr, typename _Tp, _Lock_policy _Lp>
  654. std::basic_ostream<_Ch, _Tr>&
  655. operator<<(std::basic_ostream<_Ch, _Tr>& __os,
  656. const __shared_ptr<_Tp, _Lp>& __p)
  657. {
  658. __os << __p.get();
  659. return __os;
  660. }
  661. // 2.2.3.10 shared_ptr get_deleter (experimental)
  662. template<typename _Del, typename _Tp, _Lock_policy _Lp>
  663. inline _Del*
  664. get_deleter(const __shared_ptr<_Tp, _Lp>& __p)
  665. {
  666. #if __cpp_rtti
  667. return static_cast<_Del*>(__p._M_get_deleter(typeid(_Del)));
  668. #else
  669. return 0;
  670. #endif
  671. }
  672. template<typename _Tp, _Lock_policy _Lp>
  673. class __weak_ptr
  674. {
  675. public:
  676. typedef _Tp element_type;
  677. __weak_ptr()
  678. : _M_ptr(0), _M_refcount() // never throws
  679. { }
  680. // Generated copy constructor, assignment, destructor are fine.
  681. // The "obvious" converting constructor implementation:
  682. //
  683. // template<typename _Tp1>
  684. // __weak_ptr(const __weak_ptr<_Tp1, _Lp>& __r)
  685. // : _M_ptr(__r._M_ptr), _M_refcount(__r._M_refcount) // never throws
  686. // { }
  687. //
  688. // has a serious problem.
  689. //
  690. // __r._M_ptr may already have been invalidated. The _M_ptr(__r._M_ptr)
  691. // conversion may require access to *__r._M_ptr (virtual inheritance).
  692. //
  693. // It is not possible to avoid spurious access violations since
  694. // in multithreaded programs __r._M_ptr may be invalidated at any point.
  695. template<typename _Tp1>
  696. __weak_ptr(const __weak_ptr<_Tp1, _Lp>& __r)
  697. : _M_refcount(__r._M_refcount) // never throws
  698. {
  699. __glibcxx_function_requires(_ConvertibleConcept<_Tp1*, _Tp*>)
  700. _M_ptr = __r.lock().get();
  701. }
  702. template<typename _Tp1>
  703. __weak_ptr(const __shared_ptr<_Tp1, _Lp>& __r)
  704. : _M_ptr(__r._M_ptr), _M_refcount(__r._M_refcount) // never throws
  705. { __glibcxx_function_requires(_ConvertibleConcept<_Tp1*, _Tp*>) }
  706. template<typename _Tp1>
  707. __weak_ptr&
  708. operator=(const __weak_ptr<_Tp1, _Lp>& __r) // never throws
  709. {
  710. _M_ptr = __r.lock().get();
  711. _M_refcount = __r._M_refcount;
  712. return *this;
  713. }
  714. template<typename _Tp1>
  715. __weak_ptr&
  716. operator=(const __shared_ptr<_Tp1, _Lp>& __r) // never throws
  717. {
  718. _M_ptr = __r._M_ptr;
  719. _M_refcount = __r._M_refcount;
  720. return *this;
  721. }
  722. __shared_ptr<_Tp, _Lp>
  723. lock() const // never throws
  724. {
  725. #ifdef __GTHREADS
  726. // Optimization: avoid throw overhead.
  727. if (expired())
  728. return __shared_ptr<element_type, _Lp>();
  729. __try
  730. {
  731. return __shared_ptr<element_type, _Lp>(*this);
  732. }
  733. __catch(const bad_weak_ptr&)
  734. {
  735. // Q: How can we get here?
  736. // A: Another thread may have invalidated r after the
  737. // use_count test above.
  738. return __shared_ptr<element_type, _Lp>();
  739. }
  740. #else
  741. // Optimization: avoid try/catch overhead when single threaded.
  742. return expired() ? __shared_ptr<element_type, _Lp>()
  743. : __shared_ptr<element_type, _Lp>(*this);
  744. #endif
  745. } // XXX MT
  746. long
  747. use_count() const // never throws
  748. { return _M_refcount._M_get_use_count(); }
  749. bool
  750. expired() const // never throws
  751. { return _M_refcount._M_get_use_count() == 0; }
  752. void
  753. reset() // never throws
  754. { __weak_ptr().swap(*this); }
  755. void
  756. swap(__weak_ptr& __s) // never throws
  757. {
  758. std::swap(_M_ptr, __s._M_ptr);
  759. _M_refcount._M_swap(__s._M_refcount);
  760. }
  761. private:
  762. // Used by __enable_shared_from_this.
  763. void
  764. _M_assign(_Tp* __ptr, const __shared_count<_Lp>& __refcount)
  765. {
  766. _M_ptr = __ptr;
  767. _M_refcount = __refcount;
  768. }
  769. template<typename _Tp1>
  770. bool
  771. _M_less(const __weak_ptr<_Tp1, _Lp>& __rhs) const
  772. { return _M_refcount < __rhs._M_refcount; }
  773. template<typename _Tp1, _Lock_policy _Lp1> friend class __shared_ptr;
  774. template<typename _Tp1, _Lock_policy _Lp1> friend class __weak_ptr;
  775. friend class __enable_shared_from_this<_Tp, _Lp>;
  776. friend class enable_shared_from_this<_Tp>;
  777. // Friend injected into namespace and found by ADL.
  778. template<typename _Tp1>
  779. friend inline bool
  780. operator<(const __weak_ptr& __lhs, const __weak_ptr<_Tp1, _Lp>& __rhs)
  781. { return __lhs._M_less(__rhs); }
  782. _Tp* _M_ptr; // Contained pointer.
  783. __weak_count<_Lp> _M_refcount; // Reference counter.
  784. };
  785. // 2.2.4.7 weak_ptr specialized algorithms.
  786. template<typename _Tp, _Lock_policy _Lp>
  787. inline void
  788. swap(__weak_ptr<_Tp, _Lp>& __a, __weak_ptr<_Tp, _Lp>& __b)
  789. { __a.swap(__b); }
  790. template<typename _Tp, _Lock_policy _Lp>
  791. class __enable_shared_from_this
  792. {
  793. protected:
  794. __enable_shared_from_this() { }
  795. __enable_shared_from_this(const __enable_shared_from_this&) { }
  796. __enable_shared_from_this&
  797. operator=(const __enable_shared_from_this&)
  798. { return *this; }
  799. ~__enable_shared_from_this() { }
  800. public:
  801. __shared_ptr<_Tp, _Lp>
  802. shared_from_this()
  803. { return __shared_ptr<_Tp, _Lp>(this->_M_weak_this); }
  804. __shared_ptr<const _Tp, _Lp>
  805. shared_from_this() const
  806. { return __shared_ptr<const _Tp, _Lp>(this->_M_weak_this); }
  807. private:
  808. template<typename _Tp1>
  809. void
  810. _M_weak_assign(_Tp1* __p, const __shared_count<_Lp>& __n) const
  811. { _M_weak_this._M_assign(__p, __n); }
  812. template<typename _Tp1>
  813. friend void
  814. __enable_shared_from_this_helper(const __shared_count<_Lp>& __pn,
  815. const __enable_shared_from_this* __pe,
  816. const _Tp1* __px)
  817. {
  818. if (__pe != 0)
  819. __pe->_M_weak_assign(const_cast<_Tp1*>(__px), __pn);
  820. }
  821. mutable __weak_ptr<_Tp, _Lp> _M_weak_this;
  822. };
  823. // The actual shared_ptr, with forwarding constructors and
  824. // assignment operators.
  825. template<typename _Tp>
  826. class shared_ptr
  827. : public __shared_ptr<_Tp>
  828. {
  829. public:
  830. shared_ptr()
  831. : __shared_ptr<_Tp>() { }
  832. template<typename _Tp1>
  833. explicit
  834. shared_ptr(_Tp1* __p)
  835. : __shared_ptr<_Tp>(__p) { }
  836. template<typename _Tp1, typename _Deleter>
  837. shared_ptr(_Tp1* __p, _Deleter __d)
  838. : __shared_ptr<_Tp>(__p, __d) { }
  839. template<typename _Tp1>
  840. shared_ptr(const shared_ptr<_Tp1>& __r)
  841. : __shared_ptr<_Tp>(__r) { }
  842. template<typename _Tp1>
  843. explicit
  844. shared_ptr(const weak_ptr<_Tp1>& __r)
  845. : __shared_ptr<_Tp>(__r) { }
  846. #if (__cplusplus < 201103L) || _GLIBCXX_USE_DEPRECATED
  847. template<typename _Tp1>
  848. explicit
  849. shared_ptr(std::auto_ptr<_Tp1>& __r)
  850. : __shared_ptr<_Tp>(__r) { }
  851. #endif
  852. template<typename _Tp1>
  853. shared_ptr(const shared_ptr<_Tp1>& __r, __static_cast_tag)
  854. : __shared_ptr<_Tp>(__r, __static_cast_tag()) { }
  855. template<typename _Tp1>
  856. shared_ptr(const shared_ptr<_Tp1>& __r, __const_cast_tag)
  857. : __shared_ptr<_Tp>(__r, __const_cast_tag()) { }
  858. template<typename _Tp1>
  859. shared_ptr(const shared_ptr<_Tp1>& __r, __dynamic_cast_tag)
  860. : __shared_ptr<_Tp>(__r, __dynamic_cast_tag()) { }
  861. template<typename _Tp1>
  862. shared_ptr&
  863. operator=(const shared_ptr<_Tp1>& __r) // never throws
  864. {
  865. this->__shared_ptr<_Tp>::operator=(__r);
  866. return *this;
  867. }
  868. #if (__cplusplus < 201103L) || _GLIBCXX_USE_DEPRECATED
  869. template<typename _Tp1>
  870. shared_ptr&
  871. operator=(std::auto_ptr<_Tp1>& __r)
  872. {
  873. this->__shared_ptr<_Tp>::operator=(__r);
  874. return *this;
  875. }
  876. #endif
  877. };
  878. // 2.2.3.8 shared_ptr specialized algorithms.
  879. template<typename _Tp>
  880. inline void
  881. swap(__shared_ptr<_Tp>& __a, __shared_ptr<_Tp>& __b)
  882. { __a.swap(__b); }
  883. template<typename _Tp, typename _Tp1>
  884. inline shared_ptr<_Tp>
  885. static_pointer_cast(const shared_ptr<_Tp1>& __r)
  886. { return shared_ptr<_Tp>(__r, __static_cast_tag()); }
  887. template<typename _Tp, typename _Tp1>
  888. inline shared_ptr<_Tp>
  889. const_pointer_cast(const shared_ptr<_Tp1>& __r)
  890. { return shared_ptr<_Tp>(__r, __const_cast_tag()); }
  891. template<typename _Tp, typename _Tp1>
  892. inline shared_ptr<_Tp>
  893. dynamic_pointer_cast(const shared_ptr<_Tp1>& __r)
  894. { return shared_ptr<_Tp>(__r, __dynamic_cast_tag()); }
  895. // The actual weak_ptr, with forwarding constructors and
  896. // assignment operators.
  897. template<typename _Tp>
  898. class weak_ptr
  899. : public __weak_ptr<_Tp>
  900. {
  901. public:
  902. weak_ptr()
  903. : __weak_ptr<_Tp>() { }
  904. template<typename _Tp1>
  905. weak_ptr(const weak_ptr<_Tp1>& __r)
  906. : __weak_ptr<_Tp>(__r) { }
  907. template<typename _Tp1>
  908. weak_ptr(const shared_ptr<_Tp1>& __r)
  909. : __weak_ptr<_Tp>(__r) { }
  910. template<typename _Tp1>
  911. weak_ptr&
  912. operator=(const weak_ptr<_Tp1>& __r) // never throws
  913. {
  914. this->__weak_ptr<_Tp>::operator=(__r);
  915. return *this;
  916. }
  917. template<typename _Tp1>
  918. weak_ptr&
  919. operator=(const shared_ptr<_Tp1>& __r) // never throws
  920. {
  921. this->__weak_ptr<_Tp>::operator=(__r);
  922. return *this;
  923. }
  924. shared_ptr<_Tp>
  925. lock() const // never throws
  926. {
  927. #ifdef __GTHREADS
  928. if (this->expired())
  929. return shared_ptr<_Tp>();
  930. __try
  931. {
  932. return shared_ptr<_Tp>(*this);
  933. }
  934. __catch(const bad_weak_ptr&)
  935. {
  936. return shared_ptr<_Tp>();
  937. }
  938. #else
  939. return this->expired() ? shared_ptr<_Tp>()
  940. : shared_ptr<_Tp>(*this);
  941. #endif
  942. }
  943. };
  944. template<typename _Tp>
  945. class enable_shared_from_this
  946. {
  947. protected:
  948. enable_shared_from_this() { }
  949. enable_shared_from_this(const enable_shared_from_this&) { }
  950. enable_shared_from_this&
  951. operator=(const enable_shared_from_this&)
  952. { return *this; }
  953. ~enable_shared_from_this() { }
  954. public:
  955. shared_ptr<_Tp>
  956. shared_from_this()
  957. { return shared_ptr<_Tp>(this->_M_weak_this); }
  958. shared_ptr<const _Tp>
  959. shared_from_this() const
  960. { return shared_ptr<const _Tp>(this->_M_weak_this); }
  961. private:
  962. template<typename _Tp1>
  963. void
  964. _M_weak_assign(_Tp1* __p, const __shared_count<>& __n) const
  965. { _M_weak_this._M_assign(__p, __n); }
  966. template<typename _Tp1>
  967. friend void
  968. __enable_shared_from_this_helper(const __shared_count<>& __pn,
  969. const enable_shared_from_this* __pe,
  970. const _Tp1* __px)
  971. {
  972. if (__pe != 0)
  973. __pe->_M_weak_assign(const_cast<_Tp1*>(__px), __pn);
  974. }
  975. mutable weak_ptr<_Tp> _M_weak_this;
  976. };
  977. _GLIBCXX_END_NAMESPACE_VERSION
  978. }
  979. }
  980. #endif // _TR1_SHARED_PTR_H

 

其主要的类关系如下所示(省略相关的类模板参数):

图1

 

从上面的类图可以清楚的看出shared_ptr内部含有一个指向被管理对象(managed object)T的指针以及一个__shared_count对象,__shared_count对象包含一个指向管理对象(manager object)的基类指针,管理对象(manager object)由具有原子属性的use_count和weak_count、指向被管理对象(managed object)T的指针、以及用来销毁被管理对象的deleter组成,以下均将用new创建后托管给shared_ptr等智能指针管理的对象叫做被管理对象(managed object);shared_ptr等智能指针内部创建的用来维护被管理对象生命周期的实例叫做管理对象(manager object)

图2

 

weak_ptr内部组成与shared_ptr类似,内部同样含有一个指向被管理对象T的指针以及一个__weak_count对象:

图3

 

从图2和图3对比可以看出,shared_ptr与weak_ptr的差异主要是由__shared_ptr与__weak_ptr体现出来的,而__shared_ptr与__weak_ptr的差异则主要是由__shared_count与__weak_count体现出来。

通过shared_ptr的构造函数,可以发现,在创建一个shared_ptr的时候需要一个new 操作符返回被管理对象的地址来初始化shared_ptr, shared_ptr在内部会构建一个_shared_count对象,由_shared_count对象的构造函数可知,创建shared_ptr的时候也动态的创建了一个管理对象_Sp_counted_base_impl:

 

  1. template<typename _Tp1> explicit __shared_ptr(_Tp1* __p)
  2. : _M_ptr(__p), _M_refcount(__p) {
  3.     __glibcxx_function_requires(_ConvertibleConcept<_Tp1*, _Tp*>)
  4.     typedef int _IsComplete[sizeof(_Tp1)];
  5.     __enable_shared_from_this_helper(_M_refcount, __p, __p);
  6. }
  7. template<typename _Ptr>
  8. __shared_count(_Ptr __p) : _M_pi(0)
  9. {
  10. __try
  11. {
  12. typedef typename std::tr1::remove_pointer<_Ptr>::type _Tp;
  13. _M_pi = new _Sp_counted_base_impl<_Ptr, _Sp_deleter<_Tp>, _Lp>(__p, _Sp_deleter<_Tp>());
  14. }
  15. __catch(...)
  16. {
  17. delete __p;
  18. __throw_exception_again;
  19. }
  20. }

 

shared_ptr内部包含一个指向被管理对象的指针_M_ptr, _Sp_counted_base_impl内部也含有一个指向被管理对象的指针_M_ptr, 它们是不是重复多余了呢?

实际上不多余,它们有各自的功能。这首先要从shared_ptr的拷贝构造或者赋值构造说起,当一个shared_ptr对象sp2是由sp1拷贝构造或者赋值构造得来的时候,实际上构造完成后sp1内部的__shared_count对象包含的指向管理对象的指针与sp2内部的__shared_count对象包含的指向管理对象的指针是相等的,也就是说当多个shared_ptr对象来管理同一个对象时,它们共同使用同一个动态分配的管理对象。这可以从下面的__share_ptr的构造函数和__shared_count的构造函数清楚的看出。

 

  1. template<typename _Tp1>
  2. __shared_ptr(const __shared_ptr<_Tp1, _Lp>& __r)
  3. : _M_ptr(__r._M_ptr), _M_refcount(__r._M_refcount) // never throws
  4. {__glibcxx_function_requires(_ConvertibleConcept<_Tp1*, _Tp*>)}
  5. __shared_count&
  6. operator=(const __shared_count& __r) // nothrow
  7. {
  8. _Sp_counted_base<_Lp>* __tmp = __r._M_pi;
  9. if (__tmp != _M_pi)
  10. {
  11. if (__tmp != 0)
  12. __tmp->_M_add_ref_copy();
  13. if (_M_pi != 0)
  14. _M_pi->_M_release();
  15. _M_pi = __tmp;
  16. }
  17. }

 

上面说说当多个shared_ptr对象来管理同一个对象时,它们共同使用同一个动态分配的管理对象,为什么上面给出的_shared_count的构造函数中出现了__tmp != _M_pi的情形呢?这在sp2未初始化时(_M_pi为0,_r._M_pi非0)便是这样的情形。

更一般的,也可以考虑这样的情形:shared_ptr实例sp1开始指向类A的实例对象a1, 另外一个shared_ptr实例sp2指向类A的实例对象a2(a1 != a2),当把sp2赋值给sp1时便会出现上面的情形。假设初始时有且仅有一个sp1指向a1, 有且仅有一个sp2指向a2; 则赋值结束时sp1与sp2均指向a2, 没有指针指向a1, sp1指向的a1以及其对应的管理对象均应该被析构。这在上面的代码中我们可以很清楚的看到:因为__tmp != _M_pi,  __tmp->_M_add_ref_copy()将会增加a2的use_count的引用计数;由于a1内部的_M_pi != 0, 将会调用其_M_release()函数:

 

 

  1. //************_Sp_counted_base*****************//
  2. void
  3. _M_add_ref_copy()
  4. { __gnu_cxx::__atomic_add_dispatch(&_M_use_count, 1); }
  5. //************_Sp_counted_base*****************//
  6. void
  7. _M_release() // nothrow
  8. {
  9. // Be race-detector-friendly. For more info see bits/c++config.
  10. _GLIBCXX_SYNCHRONIZATION_HAPPENS_BEFORE(&_M_use_count);
  11. if (__gnu_cxx::__exchange_and_add_dispatch(&_M_use_count, -1) == 1)
  12. {
  13. _GLIBCXX_SYNCHRONIZATION_HAPPENS_AFTER(&_M_use_count);
  14. _M_dispose();
  15. // There must be a memory barrier between dispose() and destroy()
  16. // to ensure that the effects of dispose() are observed in the
  17. // thread that runs destroy().
  18. // See http://gcc.gnu.org/ml/libstdc++/2005-11/msg00136.html
  19. if (_Mutex_base<_Lp>::_S_need_barriers)
  20. {
  21. __atomic_thread_fence (__ATOMIC_ACQ_REL);
  22. }
  23. // Be race-detector-friendly. For more info see bits/c++config.
  24. _GLIBCXX_SYNCHRONIZATION_HAPPENS_BEFORE(&_M_weak_count);
  25. if (__gnu_cxx::__exchange_and_add_dispatch(&_M_weak_count, -1) == 1)
  26. {
  27. _GLIBCXX_SYNCHRONIZATION_HAPPENS_AFTER(&_M_weak_count);
  28. _M_destroy();
  29. }
  30. }
  31. }
  32. //************_Sp_counted_base*****************//
  33. // Called when _M_use_count drops to zero, to release the resources
  34. // managed by *this.
  35. virtual void
  36. _M_dispose() = 0; // nothrow
  37. // Called when _M_weak_count drops to zero.
  38. virtual void
  39. _M_destroy() // nothrow
  40. { delete this; }
  41. //************_Sp_counted_base_impl*************//
  42. virtual void
  43. _M_dispose() // nothrow
  44. { _M_del(_M_ptr); }

 

_M_release()函数首先对a1的use_count减去1,并对比减操作之前的值,如果减之前是1,说明减后是0,a1没有任何shared_ptr指针指向它了,应该将a1对象销毁,于是调用_M_dispose()函数销毁a1; 同时对a1的weak_count减去1,也对比减操作之前的值,如果减之前是1,说明减后是0,a1没有weak_ptr指向它了,应该将管理对象销毁,于是调用_M_destroy()销毁了管理对象。这就可以解答为什么图2所示中shared_ptr内部含有两个指向被管理对象的指针了:__shared_ptr直接包含的裸指针是为了实现一般指针的->,*等操作,通过__shared_count间接包含的指针是为了管理对象的生命周期,回收相关资源。

换句话说,__shared_count内部的use_count主要用来标记被管理对象的生命周期,weak_count主要用来标记管理对象的生命周期。

当一个shared_ptr超出作用域被销毁时,它会调用其_share_count的_M_release()对use_count和weak_count进行自减并判断是否需要释放管理对象和被管理对象,这是RAII原理的核心体现:

 

  1. ~__shared_count() // nothrow
  2. {
  3. if (_M_pi != 0)
  4. _M_pi->_M_release();
  5. }

 

对于weak_ptr, 其对应的__weak_count的拷贝构造函数如下:

 

  1. //************_Sp_counted_base*****************//
  2. void
  3. _M_weak_add_ref() // nothrow
  4. { __gnu_cxx::__atomic_add_dispatch(&_M_weak_count, 1); }
  5. //************_Sp_counted_base*****************//
  6. void
  7. _M_weak_release() // nothrow
  8. {
  9. // Be race-detector-friendly. For more info see bits/c++config.
  10. _GLIBCXX_SYNCHRONIZATION_HAPPENS_BEFORE(&_M_weak_count);
  11. if (__gnu_cxx::__exchange_and_add_dispatch(&_M_weak_count, -1) == 1)
  12. {
  13. _GLIBCXX_SYNCHRONIZATION_HAPPENS_AFTER(&_M_weak_count);
  14. if (_Mutex_base<_Lp>::_S_need_barriers)
  15. {
  16. // See _M_release(),
  17. // destroy() must observe results of dispose()
  18. __atomic_thread_fence (__ATOMIC_ACQ_REL);
  19. }
  20. _M_destroy();
  21. }
  22. }
  23. __weak_count<_Lp>&
  24. operator=(const __shared_count<_Lp>& __r) // nothrow
  25. {
  26. _Sp_counted_base<_Lp>* __tmp = __r._M_pi;
  27. if (__tmp != 0)
  28. __tmp->_M_weak_add_ref();
  29. if (_M_pi != 0)
  30. _M_pi->_M_weak_release();
  31. _M_pi = __tmp;
  32. return *this;
  33. }
  34. __weak_count<_Lp>&
  35. operator=(const __weak_count<_Lp>& __r) // nothrow
  36. {
  37. _Sp_counted_base<_Lp>* __tmp = __r._M_pi;
  38. if (__tmp != 0)
  39.  __tmp->_M_weak_add_ref();
  40. if (_M_pi != 0)
  41. _M_pi->_M_weak_release();
  42. _M_pi = __tmp;
  43. return *this;
  44. }
  45. __weak_count<_Lp>&
  46. operator=(const __shared_count<_Lp>& __r) // nothrow
  47. {
  48.     _Sp_counted_base<_Lp>* __tmp = __r._M_pi;
  49.     if (__tmp != 0)
  50.       __tmp->_M_weak_add_ref();
  51.     if (_M_pi != 0)
  52.       _M_pi->_M_weak_release();
  53.     _M_pi = __tmp;  
  54.     return *this;
  55. }
  56. ~__weak_count() // nothrow
  57. {
  58. if (_M_pi != 0)
  59. _M_pi->_M_weak_release();
  60. }

 

从上面可以看出:

  • __weak_count相关的赋值拷贝以及析构函数均只会影响到weak_count的值,对use_count没有影响;当weak_count为0时,释放管理对象。也就是说__weak_ptr不影响被管理对象的生命周期。同时由于__weak_ptr没有像__shared_ptr那样实现*,->等常见指针相关操作符,__weak_ptr不能直接操作被管理对象
  • __weak_count自身间的赋值以及__shared_count对__weak_count的赋值时,它们都具有同样的指向管理对象的指针;也就是说当多个__weak_ptr和__shared_ptr指向同一个被管理对象时,它们共享同一个管理对象,这就保证了可以通过__weak_ptr可以判断__shared_ptr指向的被管理对象是否存在以及获取到被管理对象的指针。

 

__shared_ptr与__weak_ptr在管理同一对象时,它们间的关系如下图4所示:

图4

 

由于weak_ptr不能直接操作被管理对象但其仍然持有指向被管理对象的指针(用来初始化内部的__weak_count对象),weak_ptr与被管理对象用虚线联接。

_weak_ptr有几个重要的成员函数:通过expired()方法来判断对象是否过期(已经被释放);通过use_count()方法返回目前有多少个__shared_ptr对象指向被管理对象;通过lock()方法返回一个指向被管理对象的__shared_ptr指针,调用者可以通过这个__shared_ptr指针来操纵被管理对象而不用担心资源泄漏;

 

  1. /*************_weak_ptr*************************/
  2. long
  3. use_count() const // never throws
  4. { return _M_refcount._M_get_use_count(); }
  5. bool
  6. expired() const // never throws
  7. { return _M_refcount._M_get_use_count() == 0; }
  8. __shared_ptr<_Tp, _Lp>
  9. lock() const // never throws
  10. {
  11. #ifdef __GTHREADS
  12. // Optimization: avoid throw overhead.
  13.     if (expired())
  14. return __shared_ptr<element_type, _Lp>();
  15.     __try
  16.     {
  17. return __shared_ptr<element_type, _Lp>(*this);
  18.     }
  19.     __catch(const bad_weak_ptr&)
  20.     {
  21.       // Q: How can we get here?
  22.        // A: Another thread may have invalidated r after the
  23.        //    use_count test above.
  24.        return __shared_ptr<element_type, _Lp>();
  25.      }
  26.     
  27. #else
  28.     // Optimization: avoid try/catch overhead when single threaded.
  29.     return expired() ? __shared_ptr<element_type, _Lp>()
  30.                      : __shared_ptr<element_type, _Lp>(*this);
  31. #endif
  32. } // XXX MT

 

当然shared_ptr也不是万能的,使用的时候也要注意到它给程序员挖的一个大坑:shared_ptr能够管理对象的生命周期,负责对象资源释放,其前提条件是所有shared_ptr共用同一个管理对象。如果多个shared_ptr使用多个管理对象来管理同一个被管理对象,这些管理对象在use_count为0时均会释放被管理对象,将会造成多个管理对象多次释放被管理对象,造成twice delete的堆错误。下面的例子在单独使用裸指针的时候没有问题,采用shared_ptr将会出现twice delete的问题:

 

 

  1. class Thing {
  2. public:
  3. void foo();
  4. void defrangulate();
  5. };
  6. void transmogrify(Thing *);
  7. int main()
  8. {
  9. Thing * t1 = new Thing;
  10. t1->foo();
  11. ...
  12. delete t1; // done with the object
  13. }
  14. ...
  15. void Thing::foo()
  16. {
  17. // we need to transmogrify this object
  18. transmogrify(this);
  19. }
  20. void transmogrify(Thing * ptr)
  21. {
  22. ptr->defrangulate();
  23. /* etc. */
  24. }
  25. //***** Use shared_ptr***************************//
  26. class Thing {
  27. public:
  28. void foo();
  29. void defrangulate();
  30. };
  31. void transmogrify(shared_ptr<Thing>);
  32. int main()
  33. {
  34. shared_ptr<Thing> t1(new Thing); // create manager object A for the Thing
  35. t1->foo();
  36. ...
  37. // Thing is supposed to get deleted when t1 goes out of scope
  38. }
  39. void Thing::foo()
  40. {
  41. // we need to transmogrify this object
  42. shared_ptr<Thing> sp_for_this(this); // create manager object B for the Thing
  43. transmogrify(sp_for_this);
  44. // Thing is supposed to get deleted when sp_for_this and other shared_ptr goes out of scope
  45. }
  46. void transmogrify(shared_ptr<Thing> ptr)
  47. {
  48. ptr->defrangulate();
  49. /* etc. */
  50. }

 

上面注释处分别创建了两个shared_ptr指针t1,sp_for_this, 它们各自有自己的管理对象,但被管理的堆内存却是一样的,这就导致在t1和sp_for_this析构时,它们各自的管理对象均会析构被管理对象,造成twice delete。

 

怎样解决上面这一广泛存在问题:当一个对象M创建后,如果一个函数f(另一个类的成员函数或是其它自由函数)的形参为M类型的智能指针,如何在对象M内部将对象M的指针作为实参传递给该函数f ? C++引入了enable_shared_from_this利用weak_ptr的特性解决了这一问题。其基本思想是通过M继承模板类enable_shared_from_this,这样对象M内部将会有一个__weak_ptr指针_M_weak_this,在第一次创建指向M的shared_ptr Pt时,通过模板特化,将会初始化_M_weak_this;这样M内部也会产生一个指向自身的weak_ptr,并且该weak_ptr内部的管理对象与Pt的管理对象是相同的(这可以从weak_ptr内部的_M_assign函数看出)。

 

 

  1. // Friend of enable_shared_from_this.
  2. template<typename _Tp1, typename _Tp2>
  3. void __enable_shared_from_this_helper(const __shared_count<>&, const enable_shared_from_this<_Tp1>*, const _Tp2*);
  4. template<typename _Tp1>
  5. explicit __shared_ptr(_Tp1* __p)
  6. : _M_ptr(__p), _M_refcount(__p)
  7. {
  8. __glibcxx_function_requires(_ConvertibleConcept<_Tp1*, _Tp*>) typedef int _IsComplete[sizeof(_Tp1)];
  9. __enable_shared_from_this_helper(_M_refcount, __p, __p);
  10. }
  11. template<typename _Tp>
  12. class enable_shared_from_this
  13. {
  14. protected:
  15. enable_shared_from_this() { }
  16. enable_shared_from_this(const enable_shared_from_this&) { }
  17. enable_shared_from_this&
  18. operator=(const enable_shared_from_this&)
  19. { return *this; }
  20. ~enable_shared_from_this() { }
  21. public:
  22. shared_ptr<_Tp>
  23. shared_from_this()
  24. { return shared_ptr<_Tp>(this->_M_weak_this); }
  25. shared_ptr<const _Tp>
  26. shared_from_this() const
  27. { return shared_ptr<const _Tp>(this->_M_weak_this); }
  28. private:
  29. template<typename _Tp1>
  30. void
  31. _M_weak_assign(_Tp1* __p, const __shared_count<>& __n) const
  32. { _M_weak_this._M_assign(__p, __n); }
  33. template<typename _Tp1>
  34. friend void
  35. __enable_shared_from_this_helper(const __shared_count<>& __pn, const enable_shared_from_this* __pe, const _Tp1* __px)
  36. {
  37. if (__pe != 0)
  38. __pe->_M_weak_assign(const_cast<_Tp1*>(__px), __pn);
  39. }
  40. mutable weak_ptr<_Tp> _M_weak_this;
  41. };
  42. _M_assign(_Tp* __ptr, const __shared_count<_Lp>& __refcount)
  43. {
  44. _M_ptr = __ptr;
  45.   _M_refcount = __refcount;
  46. }

 

 

 

这样,在M内部,当需要传递指向M的智能指针时,可以通过继承而来的shared_from_this方法获取到指向M的智能指针而不会发生内存泄漏。上面示例中改写后的正确代码为:

 

 

  1. class Thing : public enable_shared_from_this<Thing> {
  2. public:
  3. void foo();
  4. void defrangulate();
  5. };
  6. int main()
  7. {
  8. // The following starts a manager object for the Thing and also
  9. // initializes the weak_ptr member that is now part of the Thing and share same manager object.
  10. shared_ptr<Thing> t1(new Thing);
  11. t1->foo();
  12. ...
  13. }
  14. void Thing::foo()
  15. {
  16. // get a shared_ptr from the weak_ptr in this object
  17. shared_ptr<Thing> sp_this = shared_from_this();
  18. transmogrify(sp_this);
  19. }
  20. void transmogrify(shared_ptr<Thing> ptr)
  21. {
  22. ptr->defrangulate();
  23. /* etc. */
  24. }

 

解决了所有的坑,shared_ptr是不是就十全十美了呢?当然不是,shared_ptr也存在不足:在采用shared_ptr<M> p(new M);形式创建p来管理M时,我们实际发现这中间有两次的动态内存分配:一次为创建被管理对象M,一次为创建管理对象;而内存分配通常是比较昂贵的操作。

 

如果频繁的需要创建指向多个不同对象的智能指针,可以采用shared_ptr<M> p(make_shared<M>);的方式,采用这种方式系统将会分配一大块内存同时存放管理对象和被管理对象,这就避免了上面所说的二次内存分配的问题,同时程序中也不会出现new操作符,符合"no naked new!"的编程倡导。当然这也有缺点,如果所有指向该对象的智能指针都销毁了,尽管对象的析构函数会被调用,析构被管理对象,但是如果还有weak_ptr指向该块对象所在的内存,存放管理对象的部分内存仍将不会被释放,因而导致在所有其他weak_ptr销毁前整块内存(尽管被管理对象已经析构了)将不会进入系统的内存池循环使用。

 

 

 

 

参考:

  1. gcc1.6源码
  2. Using C++ 11's Smart Pointers by David Kieras, EECS Department, University of Michigan


 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/知新_RL/article/detail/206229
推荐阅读
相关标签
  

闽ICP备14008679号