shared_ptr底层原理

C++
Author

0warning0error

Published

April 7, 2025

shared_ptr 原理是引用计数。每多一个shared指针指向同一个对象时,引用+1,而析构则相反,如果计数为零,则保存的指针被删除。

那shared_ptr 内部是什么样的呢?我们可以看GCC库中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; // 移除数组类型的最顶层维度,返回数组元素的类型。

    public:

      friend class __weak_ptr<_Tp, _Lp>;

    private:
      // ... 中间省略很多东西
      element_type*    _M_ptr;         // Contained pointer.
      __shared_count<_Lp>  _M_refcount;    // Reference counter.
    };

可以看到,shared 指针内部是有2个指针,第一个是指向原始对象的指针,第二个是引用计数的模块。

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) { }

    private:
        _Sp_counted_base(_Sp_counted_base const&) = delete;
        _Sp_counted_base& operator=(_Sp_counted_base const&) = delete;
        // _Atomic_word 是能够进行原子操作的最小类型,可能是int , long 等。
        _Atomic_word  _M_use_count;     // #shared
        _Atomic_word  _M_weak_count;    // #weak + (#shared != 0)
};

template<_Lock_policy _Lp>
class __shared_count
{
    public:
        constexpr __shared_count() noexcept : _M_pi(0)
        { }
    // 省略一大堆东西
    private:
        friend class __weak_count<_Lp>;
        _Sp_counted_base<_Lp>*  _M_pi;
};


template<typename _Ptr, typename _Deleter, typename _Alloc, _Lock_policy _Lp>
class _Sp_counted_deleter final : public _Sp_counted_base<_Lp>
{
    class _Impl : _Sp_ebo_helper<0, _Deleter>, _Sp_ebo_helper<1, _Alloc>
    {
        typedef _Sp_ebo_helper<0, _Deleter> _Del_base;
        typedef _Sp_ebo_helper<1, _Alloc>   _Alloc_base;

        public:
        _Impl(_Ptr __p, _Deleter __d, const _Alloc& __a) noexcept
        : _Del_base(std::move(__d)), _Alloc_base(__a), _M_ptr(__p)
        { }

        _Deleter& _M_del() noexcept { return _Del_base::_S_get(*this); }
        _Alloc& _M_alloc() noexcept { return _Alloc_base::_S_get(*this); }

        _Ptr _M_ptr;
    };
    // 省略一大堆东西
    private:

      _Impl _M_impl;
};

基础的_Sp_counted_base 类,有原子类型的 强引用计数和弱引用计数。 其有2个派生类