std::shared_ptr

一、shared_ptr(_Yp* __p)分析 #

1. 初始化 #

 1// /usr/include/c++/12.2.0/bits/shared_ptr.h
 2
 3  template<typename _Tp>
 4    class shared_ptr : public __shared_ptr<_Tp>
 5    {
 6    ...
 7    public:
 8    ...
 9      /**
10       *  @brief  Construct a %shared_ptr that owns the pointer @a __p.
11       *  @param  __p  A pointer that is convertible to element_type*.
12       *  @post   use_count() == 1 && get() == __p
13       *  @throw  std::bad_alloc, in which case @c delete @a __p is called.
14       */
15      template<typename _Yp, typename = _Constructible<_Yp*>>
16	explicit
17	shared_ptr(_Yp* __p) : __shared_ptr<_Tp>(__p) { }
18    ...
19    }
 1// /usr/include/c++/12.2.0/tr1/shared_ptr.h
 2
 3  // A smart pointer with reference-counted copy semantics.  The
 4  // object pointed to is deleted when the last shared_ptr pointing to
 5  // it is destroyed or reset.
 6  template<typename _Tp, _Lock_policy _Lp>
 7    class __shared_ptr
 8    {
 9    public:
10
11      template<typename _Tp1>
12        explicit
13        __shared_ptr(_Tp1* __p)
14	: _M_ptr(__p), _M_refcount(__p)
15        {
16	  __glibcxx_function_requires(_ConvertibleConcept<_Tp1*, _Tp*>)
17	  typedef int _IsComplete[sizeof(_Tp1)];
18	  __enable_shared_from_this_helper(_M_refcount, __p, __p);
19	}
20    ...
21      _Tp*         	   _M_ptr;         // Contained pointer.
22      __shared_count<_Lp>  _M_refcount;    // Reference counter.
23    };
  • __shared_ptr创建时创建了__shared_count
  • __shared_count创建时,new了一个_Sp_counted_ptr
 1// /usr/include/c++/12.2.0/bits/shared_ptr_base.h
 2  template<_Lock_policy _Lp>
 3    class __shared_count
 4    {
 5    public:
 6    ...
 7      template<typename _Ptr>
 8        explicit
 9	__shared_count(_Ptr __p) : _M_pi(0)
10	{
11	  __try
12	    {
13	      _M_pi = new _Sp_counted_ptr<_Ptr, _Lp>(__p);
14	    }
15	  __catch(...)
16	    {
17	      delete __p;
18	      __throw_exception_again;
19	    }
20	}
21    }

2. 析构 #

  • 调用栈
1std::_Sp_counted_ptr<testS*, (__gnu_cxx::_Lock_policy)2>::_M_dispose(std::_Sp_counted_ptr<testS*, (__gnu_cxx::_Lock_policy)2> * const this) (/usr/include/c++/12.2.0/bits/shared_ptr_base.h:428)
2std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release(std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2> * const this) (/usr/include/c++/12.2.0/bits/shared_ptr_base.h:346)
3std::__shared_count<(__gnu_cxx::_Lock_policy)2>::~__shared_count(std::__shared_count<(__gnu_cxx::_Lock_policy)2> * const this) (/usr/include/c++/12.2.0/bits/shared_ptr_base.h:1071)
4std::__shared_ptr<testS, (__gnu_cxx::_Lock_policy)2>::~__shared_ptr(std::__shared_ptr<testS, (__gnu_cxx::_Lock_policy)2> * const this) (/usr/include/c++/12.2.0/bits/shared_ptr_base.h:1524)
5std::shared_ptr<testS>::~shared_ptr(std::shared_ptr<testS> * const this) (/usr/include/c++/12.2.0/bits/shared_ptr.h:175)
  • 由于__shared_count__shared_ptr的成员变量,所以在释放__shared_ptr的时候就会进行释放
 1// /usr/include/c++/12.2.0/tr1/shared_ptr.h
 2
 3  template<_Lock_policy _Lp = __default_lock_policy>
 4    class __shared_count
 5    {
 6    public:
 7    ...
 8      ~__shared_count() // nothrow
 9      {
10	if (_M_pi != 0)
11	  _M_pi->_M_release();
12      }
13    ...
14    private:
15    ...
16      _Sp_counted_base<_Lp>*  _M_pi;
17    };
  • _M_release
 1// /usr/include/c++/12.2.0/bits/shared_ptr_base.h
 2  template<>
 3    inline void
 4    _Sp_counted_base<_S_atomic>::_M_release() noexcept
 5    {
 6        ...
 7	  if (__atomic_load_n(__both_counts, __ATOMIC_ACQUIRE) == __unique_ref)
 8	    {
 9	      // Both counts are 1, so there are no weak references and
10	      // we are releasing the last strong reference. No other
11	      // threads can observe the effects of this _M_release()
12	      // call (e.g. calling use_count()) without a data race.
13	      _M_weak_count = _M_use_count = 0;
14	      _GLIBCXX_SYNCHRONIZATION_HAPPENS_AFTER(&_M_use_count);
15	      _GLIBCXX_SYNCHRONIZATION_HAPPENS_AFTER(&_M_weak_count);
16	      _M_dispose();
17	      _M_destroy();
18	      return;
19	    }
20        ...
21    }
22    ...
23}
  • _M_dispose_Sp_counted_ptr继承了_Sp_counted_base,上面的_M_pi实际上是使用了_Sp_counted_ptr的方法
  • 直接调用delete
 1// /usr/include/c++/12.2.0/tr1/shared_ptr.h
 2  // Counted ptr with no deleter or allocator support
 3  template<typename _Ptr, _Lock_policy _Lp>
 4    class _Sp_counted_ptr final : public _Sp_counted_base<_Lp>
 5    {
 6    public:
 7    ...
 8      virtual void
 9      _M_dispose() noexcept
10      { delete _M_ptr; }
11    }

3. 使用构造函数的注意事项 #

3.1. 不能使用栈变量进行初始化 #

  • 由于最终会调用delete,使用栈变量不能delete,会崩溃
1void func() {
2    testS a;
3    auto test = std::shared_ptr<testS>(&a);     // 这样定义会崩溃
4}

3.2. 不能对同一个指针进行多次初始化 #

  • shared_ptr从源码上看只是托管了堆上的指针的生命周期,并不会进行拷贝,如果使用多个shared_ptr托管,会导致析构的时候多次delete
1void func() {
2    auto a = new testS();
3    auto test = std::shared_ptr<testS>(a);
4    auto test1 = std::shared_ptr<testS>(a); // 这里会造成重复delete
5}

二、shared_ptr(_Yp* __p, _Deleter __d) #

1. 初始化 #

  • 调用栈
1std::_Sp_ebo_helper<0, main(int, char**)::<lambda(testS*)>, true>::_Sp_ebo_helper(struct {...} &&)(std::_Sp_ebo_helper<0, main(int, char**)::<lambda(testS*)>, true> * const this, struct {...} && __tp) (/usr/include/c++/12.2.0/bits/shared_ptr_base.h:471)
2std::_Sp_counted_deleter<testS*, main(int, char**)::<lambda(testS*)>, std::allocator<void>, (__gnu_cxx::_Lock_policy)2>::_Impl::_Impl(testS *, struct {...}, const std::allocator<void> &)(std::_Sp_counted_deleter<testS*, main(int, char**)::<lambda(testS*)>, std::allocator<void>, (__gnu_cxx::_Lock_policy)2>::_Impl * const this, testS * __p, struct {...} __d, const std::allocator<void> & __a) (/usr/include/c++/12.2.0/bits/shared_ptr_base.h:503)
3std::_Sp_counted_deleter<testS*, main(int, char**)::<lambda(testS*)>, std::allocator<void>, (__gnu_cxx::_Lock_policy)2>::_Sp_counted_deleter(testS *, struct {...}, const std::allocator<void> &)(std::_Sp_counted_deleter<testS*, main(int, char**)::<lambda(testS*)>, std::allocator<void>, (__gnu_cxx::_Lock_policy)2> * const this, testS * __p, struct {...} __d, const std::allocator<void> & __a) (/usr/include/c++/12.2.0/bits/shared_ptr_base.h:521)
4std::__shared_count<(__gnu_cxx::_Lock_policy)2>::__shared_count<testS*, main(int, char**)::<lambda(testS*)>, std::allocator<void> >(testS *, struct {...}, std::allocator<void>)(std::__shared_count<(__gnu_cxx::_Lock_policy)2> * const this, testS * __p, struct {...} __d, std::allocator<void> __a) (/usr/include/c++/12.2.0/bits/shared_ptr_base.h:952)
5std::__shared_count<(__gnu_cxx::_Lock_policy)2>::__shared_count<testS*, main(int, char**)::<lambda(testS*)> >(testS *, struct {...})(std::__shared_count<(__gnu_cxx::_Lock_policy)2> * const this, testS * __p, struct {...} __d) (/usr/include/c++/12.2.0/bits/shared_ptr_base.h:939)
6std::__shared_ptr<testS, (__gnu_cxx::_Lock_policy)2>::__shared_ptr<testS, main(int, char**)::<lambda(testS*)> >(testS *, struct {...})(std::__shared_ptr<testS, (__gnu_cxx::_Lock_policy)2> * const this, testS * __p, struct {...} __d) (/usr/include/c++/12.2.0/bits/shared_ptr_base.h:1478)
7std::shared_ptr<testS>::shared_ptr<testS, main(int, char**)::<lambda(testS*)> >(testS *, struct {...})(std::shared_ptr<testS> * const this, testS * __p, struct {...} __d) (/usr/include/c++/12.2.0/bits/shared_ptr.h:232)
  • 首先是构造函数
 1      /**
 2       *  @brief  Construct a %shared_ptr that owns the pointer @a __p
 3       *          and the deleter @a __d.
 4       *  @param  __p  A pointer.
 5       *  @param  __d  A deleter.
 6       *  @post   use_count() == 1 && get() == __p
 7       *  @throw  std::bad_alloc, in which case @a __d(__p) is called.
 8       *
 9       *  Requirements: _Deleter's copy constructor and destructor must
10       *  not throw
11       *
12       *  __shared_ptr will release __p by calling __d(__p)
13       */
14      template<typename _Yp, typename _Deleter,
15	       typename = _Constructible<_Yp*, _Deleter>>
16	shared_ptr(_Yp* __p, _Deleter __d)
17        : __shared_ptr<_Tp>(__p, std::move(__d)) { }

注意事项 #

1. 自定义delete必须删除传入的指针 #

  • 最终析构会调用传入的delete函数,不会进行其他操作,所以需要在函数内自己调用delete或其他释放,不能只处理其他的逻辑
  • 不调用delete就会存在内存泄漏
1auto test = std::shared_ptr<testS>(new testS(), [](testS* x) {
2    // 处理其他逻辑
3    if (x->temp) {
4        delete (uint64_t*)(x->temp);
5        x->temp = nullptr;
6    }
7    delete x;   // 这一行必须
8});