当前位置:   article > 正文

shared_ptr源码分析

shared_ptr源码分析
// 引用计数器的同步方式, 单线程情形无需同步, 多线程下如支持原子操作则使用atomic, 否则退化为锁
enum _Lock_policy { _S_single, _S_mutex, _S_atomic };

static const _Lock_policy __default_lock_policy =
#ifndef __GTHREADS
    _S_single;
#elif defined _GLIBCXX_HAVE_ATOMIC_LOCK_POLICY
    _S_atomic;
#else
    _S_mutex;
#endif

// _Lock_policy枚举将用来模板特化具体的_Mutex_base
// TODO 为什么atomic不需要使用barrier?
template <_Lock_policy _Lp>
class _Mutex_base {
 protected:
  // The atomic policy uses fully-fenced builtins, single doesn't care.
  // TODO
  enum { _S_need_barriers = 0 };
};

// TODO
// template <>
// class _Mutex_base<_S_mutex> : public __gnu_cxx::__mutex {
//  protected:
//   enum { _S_need_barriers = 1 };
// };

// 引用计数器的父类
// 这个基类的设计非常巧妙, 其目的是区分两种实现子类, 主要是区分由指针构造shared_ptr
// 和直接make_shared的实现, 直接make_shared将对象和control block一次性分配在同一块内存中,
// 而由构造器产生的shared_ptr只需要维护一个指针即可
// 同时这种封装将子类异构的模板封装了起来, 阻止了模板化扩散, 简化和解耦了程序结构, 对于__shared_count是隐式的
// 代价是虚函数的成本
template <_Lock_policy _Lp = __default_lock_policy>
class _Sp_counted_base : public _Mutex_base<_Lp> {
 public:
  // TODO 为什么_M_weak_count要设置为1?
  _Sp_counted_base() noexcept : _M_use_count(1), _M_weak_count(1) {}

  virtual ~_Sp_counted_base() noexcept {}

  // 这里居然是直接返回void* (TODO 怎么保证类型安全?)
  virtual void* _M_get_deleter(const std::type_info&) noexcept = 0;

  // 每次拷贝shared_ptr, _M_use_count+1
  // 注意这里形成了acq-rel顺序 (TODO 为什么不是relax?)
  void _M_add_ref_copy() { __gnu_cxx::__atomic_add_dispatch(&_M_use_count, 1); }

  // 注意这两个操作区分开来了, 其目的应该是所有的shared_ptr释放后,
  // 应当立即释放维护的对象, 但不释放计数器本身, 当所有的weak_ptr释放后,
  // 再释放计数器本身
  virtual void _M_dispose() noexcept = 0;
  virtual void _M_destroy() noexcept { delete this; }

  // TODO
  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();
      }
    }
  }

  // 返回引用计数, 原子计数
  // 注意这里提到的`no synchronization with other threads`
  // 首先relaxed会产生synchronization吗, 不会, 不仅不构成happens-before关系, 也不构成synchronization-with关系
  // 这里不使用barrier是有意为之, TODO
  // decrementing the shared_ptr counters requires acquire -
  // release synchronization with the destructor
  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:
  // 引用计数
  _Atomic_word _M_use_count;
};

// 引用计数器
template <_Lock_policy _Lp>
class __shared_count {
 private:
  _Sp_counted_base<_Lp>* _M_pi;
};

// shared_ptr会直接public继承__shared_ptr
// 单独提出一个__shared_ptr的目的是封装LP这个模板参数, 其中LP会传递给__shared_count
// __shared_ptr持有一个元素指针和引用计数器
template <typename _Tp, _Lock_policy _Lp = __default_lock_policy>
class __shared_ptr {
 public:
  // (1) T=>T (2) T[]=>T
  using element_type = typename remove_extent<_Tp>::type;

 private:
  // 元素指针
  // 注意类型不是T, 是element_type, 为了支持数组
  element_type* ptr;
  // 引用计数器, 也就是所谓的control block
  __shared_count<_Lp> _M_refcount;
};

// 摘自标准提案对于shared_ptr的定义和api标准, 对于理解shared_ptr非常重要

// A shared_ptr can share ownership of an object while storing a pointer to another object. This feature can be used to
// point to member objects while owning the object they belong to. The stored pointer is the one accessed by get(), the
// dereference and the comparison operators. The managed pointer is the one passed to the deleter when use count reaches
// zero.

// A shared_ptr may also own no objects, in which case it is called empty (an empty shared_ptr may have a non-null
// stored pointer if the aliasing constructor was used to create it).

// All specializations of shared_ptr meet the requirements of CopyConstructible, CopyAssignable, and LessThanComparable
// and are contextually convertible to bool.

// All member functions (including copy constructor and copy assignment) can be called by multiple threads on different
// instances of shared_ptr without additional synchronization even if these instances are copies and share ownership of
// the same object. If multiple threads of execution access the same shared_ptr without synchronization and any of those
// accesses uses a non-const member function of shared_ptr then a data race will occur; the shared_ptr overloads of
// atomic functions can be used to prevent the data race.
template <typename T>
class shared_ptr {
  // Constructs a shared_ptr with no managed object, i.e. empty shared_ptr
  // constexpr shared_ptr() noexcept;
  // constexpr shared_ptr( std::nullptr_t ) noexcept;

  // Constructs a shared_ptr with ptr as the pointer to the managed object.
  // Y* must be convertible to T*.
  // template< class Y >
  // explicit shared_ptr( Y* ptr );

  // Constructs a shared_ptr with ptr as the pointer to the managed object.
  // Uses the specified deleter d as the deleter. The expression d(ptr) must be well formed, have well-defined behavior
  // and not throw any exceptions. The construction of d and of the stored deleter from d must not throw exceptions.
  // These constructors additionally do not participate in overload resolution if the expression d(ptr) is not
  // well-formed, or if std::is_move_constructible<D>::value is false.
  // template< class Y, class Deleter >
  // shared_ptr( Y* ptr, Deleter d );

  // Constructs a shared_ptr which shares ownership of the object managed by r. If r manages no object, *this manages no
  // object too. The template overload doesn't participate in overload resolution if Y* is not compatible with T*
  // shared_ptr( const shared_ptr& r ) noexcept;
  // template< class Y >
  // shared_ptr( const shared_ptr<Y>& r ) noexcept;

  // Move-constructs a shared_ptr from r. After the construction, *this contains a copy of the previous state of r, r is
  // empty and its stored pointer is null. The template overload doesn't participate in overload resolution if Y* is not
  // compatible with (since C++17) T*.
  // shared_ptr( shared_ptr&& r ) noexcept;
  // template< class Y >
  // shared_ptr(shared_ptr<Y>&& r ) noexcept;

  // operator= assigns the shared_ptr
  // reset replaces the managed object
  // swap swaps the managed objects
  // get returns the stored pointer
  // operator*
  // operator-> dereferences the stored pointer
  // use_count returns the number of shared_ptr objects referring to the same managed object
  // operator bool checks if the stored pointer is not null

 private:
};

#include <memory>

int main() {
  std::shared_ptr<int> p();
  //
}

  • 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
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/206253
推荐阅读
相关标签
  

闽ICP备14008679号