gcc5.4.0 shared_ptr源码阅读--引用计数

引言

本文探究在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类代码,完整的在文末

template <typename _Tp>
  class shared_ptr : public __shared_ptr<_Tp>
  {

  public:
    /**
       *  @brief  Construct an empty %shared_ptr.
       *  @post   use_count()==0 && get()==0
       */
    constexpr shared_ptr() noexcept
        : __shared_ptr<_Tp>() {}

    shared_ptr(const shared_ptr &) noexcept = default;

    /**
       *  @brief  Construct a %shared_ptr that owns the pointer @a __p.
       *  @param  __p  A pointer that is convertible to element_type*.
       *  @post   use_count() == 1 && get() == __p
       *  @throw  std::bad_alloc, in which case @c delete @a __p is called.
       */
    template <typename _Tp1>
    explicit shared_ptr(_Tp1 *__p)
        : __shared_ptr<_Tp>(__p) {}

    /**
       *  @brief  Move-constructs a %shared_ptr instance from @a __r.
       *  @param  __r  A %shared_ptr rvalue.
       *  @post   *this contains the old value of @a __r, @a __r is empty.
       */
    shared_ptr(shared_ptr &&__r) noexcept
        : __shared_ptr<_Tp>(std::move(__r)) {}

    /**
       *  @brief  Constructs a %shared_ptr that shares ownership with @a __r
       *          and stores a copy of the pointer stored in @a __r.
       *  @param  __r  A weak_ptr.
       *  @post   use_count() == __r.use_count()
       *  @throw  bad_weak_ptr when __r.expired(),
       *          in which case the constructor has no effect.
       */
    template <typename _Tp1>
    explicit shared_ptr(const weak_ptr<_Tp1> &__r)
        : __shared_ptr<_Tp>(__r) {}

  private:

    template <typename _Tp1, typename _Alloc, typename... _Args>
    friend shared_ptr<_Tp1>
    allocate_shared(const _Alloc &__a, _Args &&... __args);

    // This constructor is non-standard, it is used by weak_ptr::lock().
    shared_ptr(const weak_ptr<_Tp> &__r, std::nothrow_t)
        : __shared_ptr<_Tp>(__r, std::nothrow) {}

    friend class weak_ptr<_Tp>;
  };

可以看出来,shared_ptr只是个包装__shared_ptr的类,具体实现需要去看__shared_ptr。除了构造函数和拷贝构造函数,该类还提供了移动语义。

顺带一提,用原始指针初始化shared_ptr在effective modern c++中是不推荐的。原始指针的操作不受引用计数约束,为降低直接释放原始指针所指资源的风险,尽量用make_shared初始化是比较好的风格。

下面是__shared_ptr精简后的源码

 template <typename _Tp, _Lock_policy _Lp>
  class __shared_ptr
      : public __shared_ptr_access<_Tp, _Lp>
  {
  public:
    using element_type = typename remove_extent<_Tp>::type;

  private:

    template <typename _Deleter>
    __shared_ptr(nullptr_t __p, _Deleter __d)
        : _M_ptr(0), _M_refcount(__p, std::move(__d))
    {
    }

    __shared_ptr(__shared_ptr &&__r) noexcept
        : _M_ptr(__r._M_ptr), _M_refcount()
    {
      _M_refcount._M_swap(__r._M_refcount);
      __r._M_ptr = 0;
    }


  private:

    element_type *_M_ptr;            // Contained pointer.
    __shared_count<_Lp> _M_refcount; // Reference counter.
  };

可以看出,引用计数是__shared_count类型。继续看下该类源码,引用计数的底层类型是_Sp_counted_base<_Lp> *

 template <_Lock_policy _Lp>
  class __shared_count
  {
  public:
    constexpr __shared_count() noexcept : _M_pi(0)
    {
    }

    template <typename _Ptr>
    explicit __shared_count(_Ptr __p) : _M_pi(0)
    {
      __try
      {
        _M_pi = new _Sp_counted_ptr<_Ptr, _Lp>(__p);
      }
      __catch(...)
      {
        delete __p;
        __throw_exception_again;
      }
    }

  private:
    friend class __weak_count<_Lp>;

    _Sp_counted_base<_Lp> *_M_pi;
  };

_Sp_counted_base类

经过上文分析,我们终于找到了use_count的底层实现类。下面我们来看下这个类

template <_Lock_policy _Lp = __default_lock_policy>
  class _Sp_counted_base
      : public _Mutex_base<_Lp>
  {
  public:
    _Sp_counted_base() noexcept
        : _M_use_count(1), _M_weak_count(1) {}

    virtual ~_Sp_counted_base() noexcept
    {
    }

    // Called when _M_use_count drops to zero, to release the resources
    // managed by *this.
    // pusidun注 这里是纯虚函数,必须实现对象的析构。具体的析构需要看下__shared_ptr那里
    virtual void
    _M_dispose() noexcept = 0;

    // Called when _M_weak_count drops to zero.
    virtual void
    _M_destroy() noexcept
    {
      delete this;
    }

    virtual void *
    _M_get_deleter(const std::type_info &) noexcept = 0;

    void
    _M_add_ref_copy()
    {
      __gnu_cxx::__atomic_add_dispatch(&_M_use_count, 1);
    }

    void
    _M_add_ref_lock();

    bool
    _M_add_ref_lock_nothrow();

    void
    _M_release() noexcept
    {
      // Be race-detector-friendly.  For more info see bits/c++config.
      _GLIBCXX_SYNCHRONIZATION_HAPPENS_BEFORE(&_M_use_count);
      // pusidun注 这里是原子操作,先_M_use_count-1,然后检查_M_use_count减掉1之前是否是1
      // 是1说明现在引用计数已经降为0了,调用_M_dispose析构掉持有对象
      if (__gnu_cxx::__exchange_and_add_dispatch(&_M_use_count, -1) == 1)
      {
        _GLIBCXX_SYNCHRONIZATION_HAPPENS_AFTER(&_M_use_count);
        _M_dispose();
        // There must be a memory barrier between dispose() and destroy()
        // to ensure that the effects of dispose() are observed in the
        // thread that runs destroy().
        // See http://gcc.gnu.org/ml/libstdc++/2005-11/msg00136.html
        if (_Mutex_base<_Lp>::_S_need_barriers)
        {
          __atomic_thread_fence(__ATOMIC_ACQ_REL);
        }

        // Be race-detector-friendly.  For more info see bits/c++config.
        _GLIBCXX_SYNCHRONIZATION_HAPPENS_BEFORE(&_M_weak_count);
        if (__gnu_cxx::__exchange_and_add_dispatch(&_M_weak_count,
                                                   -1) == 1)
        {
          _GLIBCXX_SYNCHRONIZATION_HAPPENS_AFTER(&_M_weak_count);
          _M_destroy();
        }
      }
    }

    void
    _M_weak_add_ref() noexcept
    {
      __gnu_cxx::__atomic_add_dispatch(&_M_weak_count, 1);
    }

    void
    _M_weak_release() noexcept
    {
      // Be race-detector-friendly. For more info see bits/c++config.
      _GLIBCXX_SYNCHRONIZATION_HAPPENS_BEFORE(&_M_weak_count);
      if (__gnu_cxx::__exchange_and_add_dispatch(&_M_weak_count, -1) == 1)
      {
        _GLIBCXX_SYNCHRONIZATION_HAPPENS_AFTER(&_M_weak_count);
        if (_Mutex_base<_Lp>::_S_need_barriers)
        {
          // See _M_release(),
          // destroy() must observe results of dispose()
          __atomic_thread_fence(__ATOMIC_ACQ_REL);
        }
        _M_destroy();
      }
    }

    long
    _M_get_use_count() const noexcept
    {
      // No memory barrier is used here so there is no synchronization
      // with other threads.
      return __atomic_load_n(&_M_use_count, __ATOMIC_RELAXED);
    }

  private:
    _Sp_counted_base(_Sp_counted_base const &) = delete;
    _Sp_counted_base &operator=(_Sp_counted_base const &) = delete;

    _Atomic_word _M_use_count;  // #shared
    _Atomic_word _M_weak_count; // #weak + (#shared != 0)
  };

重点是42行的_M_release() 方法。

该方法中,对use_count进行增减、比较是原子操作。这就说明,在多线程中,shared_ptr的引用计数本身是线程安全的。但是,_M_dispose()的线程安全性却无法得到保证(并没有同步措施处理data race情况)。也就是说,shared_ptr管理的内存,在多线程环境下需要关注析构细节。

附文中详细源码

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         : _M_ptr(0), _M_refcount(__p, std::move(__d), std::move(__a))
 79     {
 80     }
 81 
 82     template <typename _Yp>
 83     __shared_ptr(const __shared_ptr<_Yp, _Lp> &__r,
 84                  element_type *__p) noexcept
 85         : _M_ptr(__p), _M_refcount(__r._M_refcount) // never throws
 86     {
 87     }
 88 
 89     __shared_ptr(const __shared_ptr &) noexcept = default;
 90     __shared_ptr &operator=(const __shared_ptr &) noexcept = default;
 91     ~__shared_ptr() = default;
 92 
 93     template <typename _Yp, typename = _Compatible<_Yp>>
 94     __shared_ptr(const __shared_ptr<_Yp, _Lp> &__r) noexcept
 95         : _M_ptr(__r._M_ptr), _M_refcount(__r._M_refcount)
 96     {
 97     }
 98 
 99     __shared_ptr(__shared_ptr &&__r) noexcept
100         : _M_ptr(__r._M_ptr), _M_refcount()
101     {
102       _M_refcount._M_swap(__r._M_refcount);
103       __r._M_ptr = 0;
104     }
105 
106     template <typename _Yp, typename = _Compatible<_Yp>>
107     __shared_ptr(__shared_ptr<_Yp, _Lp> &&__r) noexcept
108         : _M_ptr(__r._M_ptr), _M_refcount()
109     {
110       _M_refcount._M_swap(__r._M_refcount);
111       __r._M_ptr = 0;
112     }
113 
114     template <typename _Yp, typename = _Compatible<_Yp>>
115     explicit __shared_ptr(const __weak_ptr<_Yp, _Lp> &__r)
116         : _M_refcount(__r._M_refcount) // may throw
117     {
118       // It is now safe to copy __r._M_ptr, as
119       // _M_refcount(__r._M_refcount) did not throw.
120       _M_ptr = __r._M_ptr;
121     }
122 
123     // If an exception is thrown this constructor has no effect.
124     template <typename _Yp, typename _Del,
125               typename = _UniqCompatible<_Yp, _Del>>
126     __shared_ptr(unique_ptr<_Yp, _Del> &&__r)
127         : _M_ptr(__r.get()), _M_refcount()
128     {
129       auto __raw = __to_address(__r.get());
130       _M_refcount = __shared_count<_Lp>(std::move(__r));
131       _M_enable_shared_from_this_with(__raw);
132     }
133 
134 #if __cplusplus <= 201402L && _GLIBCXX_USE_DEPRECATED
135   protected:
136     // If an exception is thrown this constructor has no effect.
137     template <typename _Tp1, typename _Del,
138               typename enable_if<__and_<
139                                      __not_<is_array<_Tp>>, is_array<_Tp1>,
140                                      is_convertible<typename unique_ptr<_Tp1, _Del>::pointer, _Tp *>>::value,
141                                  bool>::type = true>
142     __shared_ptr(unique_ptr<_Tp1, _Del> &&__r, __sp_array_delete)
143         : _M_ptr(__r.get()), _M_refcount()
144     {
145       auto __raw = __to_address(__r.get());
146       _M_refcount = __shared_count<_Lp>(std::move(__r));
147       _M_enable_shared_from_this_with(__raw);
148     }
149 
150   public:
151 #endif
152 
153 #if _GLIBCXX_USE_DEPRECATED
154 #pragma GCC diagnostic push
155 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
156     // Postcondition: use_count() == 1 and __r.get() == 0
157     template <typename _Yp, typename = _Compatible<_Yp>>
158     __shared_ptr(auto_ptr<_Yp> &&__r);
159 #pragma GCC diagnostic pop
160 #endif
161 
162     constexpr __shared_ptr(nullptr_t) noexcept : __shared_ptr()
163     {
164     }
165 
166     template <typename _Yp>
167     _Assignable<_Yp>
168     operator=(const __shared_ptr<_Yp, _Lp> &__r) noexcept
169     {
170       _M_ptr = __r._M_ptr;
171       _M_refcount = __r._M_refcount; // __shared_count::op= doesn't throw
172       return *this;
173     }
174 
175 #if _GLIBCXX_USE_DEPRECATED
176 #pragma GCC diagnostic push
177 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
178     template <typename _Yp>
179     _Assignable<_Yp>
180     operator=(auto_ptr<_Yp> &&__r)
181     {
182       __shared_ptr(std::move(__r)).swap(*this);
183       return *this;
184     }
185 #pragma GCC diagnostic pop
186 #endif
187 
188     __shared_ptr &
189     operator=(__shared_ptr &&__r) noexcept
190     {
191       __shared_ptr(std::move(__r)).swap(*this);
192       return *this;
193     }
194 
195     template <class _Yp>
196     _Assignable<_Yp>
197     operator=(__shared_ptr<_Yp, _Lp> &&__r) noexcept
198     {
199       __shared_ptr(std::move(__r)).swap(*this);
200       return *this;
201     }
202 
203     template <typename _Yp, typename _Del>
204     _UniqAssignable<_Yp, _Del>
205     operator=(unique_ptr<_Yp, _Del> &&__r)
206     {
207       __shared_ptr(std::move(__r)).swap(*this);
208       return *this;
209     }
210 
211     void
212     reset() noexcept
213     {
214       __shared_ptr().swap(*this);
215     }
216 
217     template <typename _Yp>
218     _SafeConv<_Yp>
219     reset(_Yp *__p) // _Yp must be complete.
220     {
221       // Catch self-reset errors.
222       __glibcxx_assert(__p == 0 || __p != _M_ptr);
223       __shared_ptr(__p).swap(*this);
224     }
225 
226     template <typename _Yp, typename _Deleter>
227     _SafeConv<_Yp>
228     reset(_Yp *__p, _Deleter __d)
229     {
230       __shared_ptr(__p, std::move(__d)).swap(*this);
231     }
232 
233     template <typename _Yp, typename _Deleter, typename _Alloc>
234     _SafeConv<_Yp>
235     reset(_Yp *__p, _Deleter __d, _Alloc __a)
236     {
237       __shared_ptr(__p, std::move(__d), std::move(__a)).swap(*this);
238     }
239 
240     element_type *
241     get() const noexcept
242     {
243       return _M_ptr;
244     }
245 
246     explicit operator bool() const // never throws
247     {
248       return _M_ptr == 0 ? false : true;
249     }
250 
251     bool
252     unique() const noexcept
253     {
254       return _M_refcount._M_unique();
255     }
256 
257     long
258     use_count() const noexcept
259     {
260       return _M_refcount._M_get_use_count();
261     }
262 
263     void
264     swap(__shared_ptr<_Tp, _Lp> &__other) noexcept
265     {
266       std::swap(_M_ptr, __other._M_ptr);
267       _M_refcount._M_swap(__other._M_refcount);
268     }
269 
270     template <typename _Tp1>
271     bool
272     owner_before(__shared_ptr<_Tp1, _Lp> const &__rhs) const noexcept
273     {
274       return _M_refcount._M_less(__rhs._M_refcount);
275     }
276 
277     template <typename _Tp1>
278     bool
279     owner_before(__weak_ptr<_Tp1, _Lp> const &__rhs) const noexcept
280     {
281       return _M_refcount._M_less(__rhs._M_refcount);
282     }
283 
284   protected:
285     // This constructor is non-standard, it is used by allocate_shared.
286     template <typename _Alloc, typename... _Args>
287     __shared_ptr(_Sp_make_shared_tag __tag, const _Alloc &__a,
288                  _Args &&... __args)
289         : _M_ptr(), _M_refcount(__tag, (_Tp *)0, __a,
290                                 std::forward<_Args>(__args)...)
291     {
292       // _M_ptr needs to point to the newly constructed object.
293       // This relies on _Sp_counted_ptr_inplace::_M_get_deleter.
294 #if __cpp_rtti
295       void *__p = _M_refcount._M_get_deleter(typeid(__tag));
296 #else
297       void *__p = _M_refcount._M_get_deleter(_Sp_make_shared_tag::_S_ti());
298 #endif
299       _M_ptr = static_cast<_Tp *>(__p);
300       _M_enable_shared_from_this_with(_M_ptr);
301     }
302 
303     template <typename _Tp1, _Lock_policy _Lp1, typename _Alloc,
304               typename... _Args>
305     friend __shared_ptr<_Tp1, _Lp1>
306     __allocate_shared(const _Alloc &__a, _Args &&... __args);
307 
308     // This constructor is used by __weak_ptr::lock() and
309     // shared_ptr::shared_ptr(const weak_ptr&, std::nothrow_t).
310     __shared_ptr(const __weak_ptr<_Tp, _Lp> &__r, std::nothrow_t)
311         : _M_refcount(__r._M_refcount, std::nothrow)
312     {
313       _M_ptr = _M_refcount._M_get_use_count() ? __r._M_ptr : nullptr;
314     }
315 
316     friend class __weak_ptr<_Tp, _Lp>;
317 
318   private:
319     template <typename _Yp>
320     using __esft_base_t = decltype(__enable_shared_from_this_base(
321         std::declval<const __shared_count<_Lp> &>(),
322         std::declval<_Yp *>()));
323 
324     // Detect an accessible and unambiguous enable_shared_from_this base.
325     template <typename _Yp, typename = void>
326     struct __has_esft_base
327         : false_type
328     {
329     };
330 
331     template <typename _Yp>
332     struct __has_esft_base<_Yp, __void_t<__esft_base_t<_Yp>>>
333         : __not_<is_array<_Tp>>
334     {
335     }; // No enable shared_from_this for arrays
336 
337     template <typename _Yp, typename _Yp2 = typename remove_cv<_Yp>::type>
338     typename enable_if<__has_esft_base<_Yp2>::value>::type
339     _M_enable_shared_from_this_with(_Yp *__p) noexcept
340     {
341       if (auto __base = __enable_shared_from_this_base(_M_refcount, __p))
342         __base->_M_weak_assign(const_cast<_Yp2 *>(__p), _M_refcount);
343     }
344 
345     template <typename _Yp, typename _Yp2 = typename remove_cv<_Yp>::type>
346     typename enable_if<!__has_esft_base<_Yp2>::value>::type
347     _M_enable_shared_from_this_with(_Yp *) noexcept
348     {
349     }
350 
351     void *
352     _M_get_deleter(const std::type_info &__ti) const noexcept
353     {
354       return _M_refcount._M_get_deleter(__ti);
355     }
356 
357     template <typename _Tp1, _Lock_policy _Lp1>
358     friend class __shared_ptr;
359     template <typename _Tp1, _Lock_policy _Lp1>
360     friend class __weak_ptr;
361 
362     template <typename _Del, typename _Tp1, _Lock_policy _Lp1>
363     friend _Del *get_deleter(const __shared_ptr<_Tp1, _Lp1> &) noexcept;
364 
365     template <typename _Del, typename _Tp1>
366     friend _Del *get_deleter(const shared_ptr<_Tp1> &) noexcept;
367 
368     element_type *_M_ptr;            // Contained pointer.
369     __shared_count<_Lp> _M_refcount; // Reference counter.
370   };

__shared_count源码

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     template <typename _Ptr>
 24     __shared_count(_Ptr __p, /* is_array = */ false_type)
 25         : __shared_count(__p)
 26     {
 27     }
 28 
 29     template <typename _Ptr>
 30     __shared_count(_Ptr __p, /* is_array = */ true_type)
 31         : __shared_count(__p, __sp_array_delete{}, allocator<void>())
 32     {
 33     }
 34 
 35     template <typename _Ptr, typename _Deleter>
 36     __shared_count(_Ptr __p, _Deleter __d)
 37         : __shared_count(__p, std::move(__d), allocator<void>())
 38     {
 39     }
 40 
 41     template <typename _Ptr, typename _Deleter, typename _Alloc>
 42     __shared_count(_Ptr __p, _Deleter __d, _Alloc __a) : _M_pi(0)
 43     {
 44       typedef _Sp_counted_deleter<_Ptr, _Deleter, _Alloc, _Lp> _Sp_cd_type;
 45       __try
 46       {
 47         typename _Sp_cd_type::__allocator_type __a2(__a);
 48         auto __guard = std::__allocate_guarded(__a2);
 49         _Sp_cd_type *__mem = __guard.get();
 50         ::new (__mem) _Sp_cd_type(__p, std::move(__d), std::move(__a));
 51         _M_pi = __mem;
 52         __guard = nullptr;
 53       }
 54       __catch(...)
 55       {
 56         __d(__p); // Call _Deleter on __p.
 57         __throw_exception_again;
 58       }
 59     }
 60 
 61     template <typename _Tp, typename _Alloc, typename... _Args>
 62     __shared_count(_Sp_make_shared_tag, _Tp *, const _Alloc &__a,
 63                    _Args &&... __args)
 64         : _M_pi(0)
 65     {
 66       typedef _Sp_counted_ptr_inplace<_Tp, _Alloc, _Lp> _Sp_cp_type;
 67       typename _Sp_cp_type::__allocator_type __a2(__a);
 68       auto __guard = std::__allocate_guarded(__a2);
 69       _Sp_cp_type *__mem = __guard.get();
 70       ::new (__mem) _Sp_cp_type(std::move(__a),
 71                                 std::forward<_Args>(__args)...);
 72       _M_pi = __mem;
 73       __guard = nullptr;
 74     }
 75 
 76 #if _GLIBCXX_USE_DEPRECATED
 77 #pragma GCC diagnostic push
 78 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
 79     // Special case for auto_ptr<_Tp> to provide the strong guarantee.
 80     template <typename _Tp>
 81     explicit __shared_count(std::auto_ptr<_Tp> &&__r);
 82 #pragma GCC diagnostic pop
 83 #endif
 84 
 85     // Special case for unique_ptr<_Tp,_Del> to provide the strong guarantee.
 86     template <typename _Tp, typename _Del>
 87     explicit __shared_count(std::unique_ptr<_Tp, _Del> &&__r) : _M_pi(0)
 88     {
 89       // _GLIBCXX_RESOLVE_LIB_DEFECTS
 90       // 2415. Inconsistency between unique_ptr and shared_ptr
 91       if (__r.get() == nullptr)
 92         return;
 93 
 94       using _Ptr = typename unique_ptr<_Tp, _Del>::pointer;
 95       using _Del2 = typename conditional<is_reference<_Del>::value,
 96                                          reference_wrapper<typename remove_reference<_Del>::type>,
 97                                          _Del>::type;
 98       using _Sp_cd_type = _Sp_counted_deleter<_Ptr, _Del2, allocator<void>, _Lp>;
 99       using _Alloc = allocator<_Sp_cd_type>;
100       using _Alloc_traits = allocator_traits<_Alloc>;
101       _Alloc __a;
102       _Sp_cd_type *__mem = _Alloc_traits::allocate(__a, 1);
103       _Alloc_traits::construct(__a, __mem, __r.release(),
104                                __r.get_deleter()); // non-throwing
105       _M_pi = __mem;
106     }
107 
108     // Throw bad_weak_ptr when __r._M_get_use_count() == 0.
109     explicit __shared_count(const __weak_count<_Lp> &__r);
110 
111     // Does not throw if __r._M_get_use_count() == 0, caller must check.
112     explicit __shared_count(const __weak_count<_Lp> &__r, std::nothrow_t);
113 
114     ~__shared_count() noexcept
115     {
116       if (_M_pi != nullptr)
117         _M_pi->_M_release();
118     }
119 
120     __shared_count(const __shared_count &__r) noexcept
121         : _M_pi(__r._M_pi)
122     {
123       if (_M_pi != 0)
124         _M_pi->_M_add_ref_copy();
125     }
126 
127     __shared_count &
128     operator=(const __shared_count &__r) noexcept
129     {
130       _Sp_counted_base<_Lp> *__tmp = __r._M_pi;
131       if (__tmp != _M_pi)
132       {
133         if (__tmp != 0)
134           __tmp->_M_add_ref_copy();
135         if (_M_pi != 0)
136           _M_pi->_M_release();
137         _M_pi = __tmp;
138       }
139       return *this;
140     }
141 
142     void
143     _M_swap(__shared_count &__r) noexcept
144     {
145       _Sp_counted_base<_Lp> *__tmp = __r._M_pi;
146       __r._M_pi = _M_pi;
147       _M_pi = __tmp;
148     }
149 
150     long
151     _M_get_use_count() const noexcept
152     {
153       return _M_pi != 0 ? _M_pi->_M_get_use_count() : 0;
154     }
155 
156     bool
157     _M_unique() const noexcept
158     {
159       return this->_M_get_use_count() == 1;
160     }
161 
162     void *
163     _M_get_deleter(const std::type_info &__ti) const noexcept
164     {
165       return _M_pi ? _M_pi->_M_get_deleter(__ti) : nullptr;
166     }
167 
168     bool
169     _M_less(const __shared_count &__rhs) const noexcept
170     {
171       return std::less<_Sp_counted_base<_Lp> *>()(this->_M_pi, __rhs._M_pi);
172     }
173 
174     bool
175     _M_less(const __weak_count<_Lp> &__rhs) const noexcept
176     {
177       return std::less<_Sp_counted_base<_Lp> *>()(this->_M_pi, __rhs._M_pi);
178     }
179 
180     // Friend function injected into enclosing namespace and found by ADL
181     friend inline bool
182     operator==(const __shared_count &__a, const __shared_count &__b) noexcept
183     {
184       return __a._M_pi == __b._M_pi;
185     }
186 
187   private:
188     friend class __weak_count<_Lp>;
189 
190     _Sp_counted_base<_Lp> *_M_pi;
191   };