当前位置:   article > 正文

GCC STL源码解析 —— shared_ptr & weak_ptr_shared_ptr 源码分析

shared_ptr 源码分析

shared ptr & weak ptr

1 主要代码

1.1 count

_Mutex_base
using __gnu_cxx::__default_lock_policy;
using __gnu_cxx::_Lock_policy;
using __gnu_cxx::_S_atomic;
using __gnu_cxx::_S_mutex;
using __gnu_cxx::_S_single;

// Empty helper class except when the template argument is _S_mutex.
template <_Lock_policy _Lp>
class _Mutex_base {
   
protected:
    // The atomic policy uses fully-fenced builtins, single doesn't care.
    enum {
    _S_need_barriers = 0 };
};

template <>
class _Mutex_base<_S_mutex> : public __gnu_cxx::__mutex {
   
protected:
    // This policy is used when atomic builtins are not available.
    // The replacement atomic operations might not have the necessary
    // memory barriers.
    enum {
    _S_need_barriers = 1 };
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

_Lock_policy相关参见备注2.3.

_Sp_counted_base
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.
    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() {
   
        if (!_M_add_ref_lock_nothrow()) __throw_bad_weak_ptr();
    }

    bool _M_add_ref_lock_nothrow() noexcept;

    void _M_release() noexcept {
   
        // Be race-detector-friendly.  For more info see bits/c++config.
        _GLIBCXX_SYNCHRONIZATION_HAPPENS_BEFORE(&_M_use_count);
        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)
};

template <>
inline bool _Sp_counted_base<_S_single>::_M_add_ref_lock_nothrow() noexcept {
   
    if (_M_use_count == 0) return false;
    ++_M_use_count;
    return true;
}

template <>
inline bool _Sp_counted_base<_S_mutex>::_M_add_ref_lock_nothrow() noexcept {
   
    __gnu_cxx::__scoped_lock sentry(*this);
    if (__gnu_cxx::__exchange_and_add_dispatch(&_M_use_count, 1) == 0) {
   
        _M_use_count = 0;
        return false;
    }
    return true;
}

template <>
inline bool _Sp_counted_base<_S_atomic>::_M_add_ref_lock_nothrow() noexcept {
   
    // Perform lock-free add-if-not-zero operation.
    _Atomic_word __count = _M_get_use_count();
    do {
   
        if (__count == 0) return false;
        // Replace the current counter value with the old value + 1, as
        // long as it's not changed meanwhile.
    } while (!__atomic_compare_exchange_n(&_M_use_count, &__count, __count + 1, true, __ATOMIC_ACQ_REL,
                                          __ATOMIC_RELAXED));
    return true;
}

template <>
inline void _Sp_counted_base<_S_single>::_M_add_ref_copy() {
   
    ++_M_use_count;
}

template <>
inline void _Sp_counted_base<_S_single>::_M_release() noexcept {
   
    if (--_M_use_count == 0) {
   
        _M_dispose();
        if (--_M_weak_count == 0) _M_destroy();
    }
}

template <>
inline void _Sp_counted_base<_S_single>::_M_weak_add_ref() noexcept {
   
    ++_M_weak_count;
}

template <>
inline void _Sp_counted_base<_S_single>::_M_weak_release() noexcept {
   
    if (--_M_weak_count == 0) _M_destroy();
}

template <>
inline long _Sp_counted_base<_S_single>::_M_get_use_count() const noexcept {
   
    return _M_use_count;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • __exchange_and_add_dispatch函数参见备注2.2.
  • 构造函数将两个成员变量_M_use_count_M_weak_count初始化为1.这里的逻辑是,当它创建的时候,自己本身就是一个引用计数。
  • _M_dispose函数是纯虚函数,当_M_use_count为0时,释放this持有的资源。
  • _M_destroy函数默认删除this,当_M_weak_count为0时调用。
  • _M_add_ref_copy函数,对_M_use_count + 1,是原子操作。
  • _M_add_ref_lock函数,主要逻辑仍然是_M_use_count + 1。和_M_add_ref_copy的区别是对不同_Lock_policy有不同的实现,包含直接加、原子操作加、加锁。
  • _M_release函数,当_M_use_count-1=0时,即_M_use_count为0时,调用_M_dispose。并当_M_use_count-1=0,即_M_weak_count为0时,调用_M_destroy
  • _M_weak_add_ref:对_M_weak_count + 1,是原子操作。
  • _M_weak_release:只对_M_weak_count - 1
  • 以上两个函数都有_Lock_policy=_M_single时的重载形式。
_Sp_counted_ptr
// Counted ptr with no deleter or allocator support
template <typename _Ptr, _Lock_policy _Lp>
class _Sp_counted_ptr final : public _Sp_counted_base<_Lp> {
   
public:
    explicit _Sp_counted_ptr(_Ptr __p) noexcept : _M_ptr(__p) {
   }

    virtual void _M_dispose() noexcept {
    delete _M_ptr; }

    virtual void _M_destroy() noexcept {
    delete this; }

    virtual void* _M_get_deleter(const std::type_info&) noexcept {
    return nullptr; }

    _Sp_counted_ptr(const _Sp_counted_ptr&) = delete;
    _Sp_counted_ptr& operator=(const _Sp_counted_ptr&) = delete;

private:
    _Ptr _M_ptr;
};

template <>
inline void _Sp_counted_ptr<nullptr_t, _S_single>::_M_dispose() noexcept {
   }

template <>
inline void _Sp_counted_ptr<nullptr_t, _S_mutex>::_M_dispose() noexcept {
   }

template <>
inline void _Sp_counted_ptr<nullptr_t, _S_atomic>::_M_dispose() noexcept {
   }

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

不支持deleter和allocator的counted ptr。

  • _M_dispose默认行为是delete _M_ptr_M_destroy默认行为是delete this。
  • 对于_Ptr=nullptr_t时,不同_Lock_policy_M_dispose的行为都是空的。
_Sp_ebo_helper
template <int _Nm, typename _Tp, bool __use_ebo = !__is_final(_Tp) && __is_empty(_Tp)>
struct _Sp_ebo_helper;

/// Specialization using EBO.
template <int _Nm, typename _Tp>
struct _Sp_ebo_helper<_Nm, _Tp, true> : private _Tp {
   
    explicit _Sp_ebo_helper(const _Tp& __tp) : _Tp(__tp) {
   }
    explicit _Sp_ebo_helper(_Tp&& __tp) : _Tp(std::move(__tp)) {
   }

    static _Tp& _S_get(_Sp_ebo_helper& __eboh) {
    return static_cast<_Tp&>(__eboh); }
};

/// Specialization not using EBO.
template <int _Nm, typename _Tp>
struct _Sp_ebo_helper<_Nm, _Tp, false> {
   
    explicit _Sp_ebo_helper(const _Tp& __tp) : _M_tp(__tp) {
   }
    explicit _Sp_ebo_helper(_Tp&& __tp) : _M_tp(std::move(__tp)) {
   }

    static _Tp& _S_get(_Sp_ebo_helper& __eboh) {
    return __eboh._M_tp; }

private:
    _Tp _M_tp;
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

在类型_Tp为final且empty的时候,使用ebo优化的类,即模板参数__use_ebo为true的时候。

  • 对于“空”类型,不存在私有变量,_S_get返回强转为_Tp类型的入参_Sp_ebo_helper
  • 对于“非空”类型,有一个_Tp类型的私有变量:_M_tp_S_get返回这个变量。
_Sp_counted_deleter
// Support for custom deleter and/or allocator
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;
    };

public:
    using __allocator_type = __alloc_rebind<_Alloc, _Sp_counted_deleter>;

    // __d(__p) must not throw.
    _Sp_counted_deleter(_Ptr __p, _Deleter __d) noexcept : _M_impl(__p, std::move(__d), _Alloc()) {
   }

    // __d(__p) must not throw.
    _Sp_counted_deleter(_Ptr __p, _Deleter __d, const _Alloc& __a) noexcept : _M_impl(__p, std::move(__d), __a) {
   }

    ~_Sp_counted_deleter() noexcept {
   }

    virtual void _M_dispose() noexcept {
    _M_impl._M_del()(_M_impl._M_ptr); }

    virtual void _M_destroy() noexcept {
   
        __allocator_type __a(_M_impl._M_alloc());
        __allocated_ptr<__allocator_type> __guard_ptr{
   __a, this};
        this->~_Sp_counted_deleter();
    }

    virtual void* _M_get_deleter(const type_info& __ti [[__gnu__::__unused__]]) noexcept {
   
#if __cpp_rtti
        // _GLIBCXX_RESOLVE_LIB_DEFECTS
        // 2400. shared_ptr's get_deleter() should use addressof()
        return __ti == typeid(_Deleter) ? std::__addressof(_M_impl._M_del()) : nullptr;
#else
        return nullptr;
#endif
    }

private:
    _Impl _M_impl;
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61

_Impl继承自_Sp_ebo_helper<0, _Deleter>作为_Del_base_Sp_ebo_helper<1, _Alloc>作为_Alloc_base

  • _M_ptr作为私有变量是被管理的对象的指针。
  • _M_del_Del_base获取一个_Deleter变量。
  • _M_alloc_Alloc_base获取一个_Alloc类型变量。

_Sp_counted_deleter继承自_Sp_counted_base

  • 唯一的私有变量是_Impl类型的。
  • 构造函数主要是将传入的数据构造一个_Impl
  • _M_dispose函数对_Ptr调用_M_del()
  • _M_destroy函数对this调用析构函数。
  • _M_get_delter,当传入的type_info类型的__ti_Deleter是同样的类型的时候,返回_M_del()的地址,否则返回nullptr。
_Sp_counted_ptr_inplace
struct _Sp_make_shared_tag {
   
private:
    template <typename _Tp, typename _Alloc, _Lock_policy _Lp>
    friend class _Sp_counted_ptr_inplace;

    static const type_info& _S_ti() noexcept _GLIBCXX_VISIBILITY(default) {
   
        alignas(type_info) static constexpr char __tag[sizeof(type_info)] = {
   };
        return reinterpret_cast<const type_info&>(__tag);
    }

    static bool _S_eq(const type_info&) noexcept;
};

template <typename _Alloc>
struct _Sp_alloc_shared_tag {
   
    const _Alloc& _M_a;
};

template <typename _Tp, typename _Alloc, _Lock_policy _Lp>
class _Sp_counted_ptr_inplace final : public _Sp_counted_base<_Lp> {
   
    class _Impl : _Sp_ebo_helper<0, _Alloc> {
   
        typedef _Sp_ebo_helper<0, _Alloc> _A_base;

    public:
        explicit _Impl(_Alloc __a) noexcept : _A_base(__a) {
   }

        _Alloc& _M_alloc() noexcept {
    return _A_base::_S_get(*this); }

        __gnu_cxx::__aligned_buffer<_Tp> _M_storage;
    };

public:
    using __allocator_type = __alloc_rebind<_Alloc, _Sp_counted_ptr_inplace>;

    // Alloc parameter is not a reference so doesn't alias anything in __args
    template <typename... _Args>
    _Sp_counted_ptr_inplace(_Alloc __a, _Args&&... __args) : _M_impl(__a) {
   
        // _GLIBCXX_RESOLVE_LIB_DEFECTS
        // 2070.  allocate_shared should use allocator_traits<A>::construct
        allocator_traits<_Alloc>::construct(__a, _M_ptr(),
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/206237?site
推荐阅读
相关标签
  

闽ICP备14008679号