当前位置 博文首页 > 文章内容

    gcc5.4.0 shared_ptr源码阅读

    作者: 栏目:未分类 时间:2020-07-17 11:08:31

    本站于2023年9月4日。收到“大连君*****咨询有限公司”通知
    说我们IIS7站长博客,有一篇博文用了他们的图片。
    要求我们给他们一张图片6000元。要不然法院告我们

    为避免不必要的麻烦,IIS7站长博客,全站内容图片下架、并积极应诉
    博文内容全部不再显示,请需要相关资讯的站长朋友到必应搜索。谢谢!

    另祝:版权碰瓷诈骗团伙,早日弃暗投明。

    相关新闻:借版权之名、行诈骗之实,周某因犯诈骗罪被判处有期徒刑十一年六个月

    叹!百花齐放的时代,渐行渐远!



    引言

    本文探究在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类

    下面是我精简的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   };

    _Sp_counted_base类

    经过上文分析,我们终于找到了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   };
    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     // 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