[STL] std::shared_ptr笔记

[STL] std::shared_ptr笔记

std::shared_ptr 简易uml(只简单包含member variable&重要member function)

[STL] std::shared_ptr笔记_第1张图片

初始化以及引起引用计数变化的原因

这里暂时省略了std::make_shared<>的初始化。使用Tp *ptr指针初始化std::shared_ptr时,如果ptr == nullptr,那么_M_ptr_M_refcount都是nullptr。否则,_M_ptr = ptr,然后申请控制块的内存。

      template<typename _Yp, typename = _SafeConv<_Yp>>
	explicit
	__shared_ptr(_Yp* __p)
	: _M_ptr(__p), _M_refcount(__p, typename is_array<_Tp>::type())
	{
	  static_assert( !is_void<_Yp>::value, "incomplete type" );
	  static_assert( sizeof(_Yp) > 0, "incomplete type" );
	  _M_enable_shared_from_this_with(__p);
	}

// 申请控制块内存&初始化
      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;
	    }
	}

初始时,_M_use_count_M_weak_count都为1。这两个字段代表shared的引用计数以及弱引用计数。引起_M_use_count_M_weak_count的情况包括:

  1. std::shared_ptr的复制构造:_M_use_count => _M_use_count + 1
  2. 复制拷贝: _M_use_count => _M_use_count + 1,同时会调用_M_release()导致_M_use_count_M_weak_count减1。
      __shared_count&
      operator=(const __shared_count& __r) noexcept
      {
	_Sp_counted_base<_Lp>* __tmp = __r._M_pi;
	if (__tmp != _M_pi)
	  {
	    if (__tmp != nullptr)
	      __tmp->_M_add_ref_copy();
	    if (_M_pi != nullptr)
	      _M_pi->_M_release();
	    _M_pi = __tmp;
	  }
	return *this;
      }
  1. reset() : 与初始化的std::shared_ptr执行swap操作,然后依赖~shared_ptr减少_M_use_count_M_weak_count
      void
      reset() noexcept
      { __shared_ptr().swap(*this); }

      ~__shared_count() noexcept
      {
	if (_M_pi != nullptr)
	  _M_pi->_M_release();
      }

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

std::weak_ptr

  template<typename _Tp>
    class shared_ptr : public __shared_ptr<_Tp>
    {
    	// ...
    	friend class weak_ptr<_Tp>;
    }

std::weak_ptr使用std::shared_ptr对象初始化,它们公用由std::shared_ptr(不为nullptr的情况下)创建的控制块。初始化完毕后_M_weak_count+1。

lock

      shared_ptr<_Tp>
      lock() const noexcept
      { return shared_ptr<_Tp>(*this, std::nothrow); }


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

      // This constructor is used by __weak_ptr::lock() and
      // shared_ptr::shared_ptr(const weak_ptr&, std::nothrow_t).
      __shared_ptr(const __weak_ptr<_Tp, _Lp>& __r, std::nothrow_t) noexcept
      : _M_refcount(__r._M_refcount, std::nothrow)
      {
	_M_ptr = _M_refcount._M_get_use_count() ? __r._M_ptr : nullptr;
      }


  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;
    }

调用栈为:
[STL] std::shared_ptr笔记_第2张图片
lock()其实就是判断_M_use_count是否大于0,如果大于0则创建一个新的shared_ptr对象,这里用到了诸如std::atomic_compare_exchange_weak的原子操作。当对_M_use_count更新成功时,使用的是memory order是memory_order_acq_rel

_M_release()内存屏障

_M_release()函数中,它的_M_dispose()函数其实是一个读操作,在当前线程使用memory fence可以确保在其之后的if条件语句重排到_M_dispose()之前。否则先delete thisdelete _M_ptr则会coredump。如果另一个线程在执行_M_weak_release()而产生data race,那么说明_M_release()_M_weak_count同步于_M_weak_release()线程的同时,因为线程__atomic_thread_fence限制了_M_dispose()的重排,weak线程也有一个__atomic_thread_fence也限制了_M_destroy()的重排,所以_M_dispose()先序于_M_destroy()

      virtual void
      _M_dispose() noexcept
      { delete _M_ptr; }

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

单线程shared_ptr实现

#pragma once
#include 

namespace TinyNet {
template <typename T> class ThreadUnsafeSharedPtr;
template <typename T> class ThreadUnsafeWeakPtr;
template <typename Tp> class shared_weak_count;

template <typename Tp> class shared_weak_count {
public:
  constexpr shared_weak_count() noexcept
      : m_use_count{0}, m_weak_count{0}, m_ptr{nullptr} {}

  template <typename Yp>
  explicit shared_weak_count(Yp *ptr)
      : m_use_count{1}, m_weak_count{1}, m_ptr{ptr} {}

  inline void add_ref_copy() { m_use_count += 1; }

  inline void add_weak_copy() { m_weak_count += 1; }

  inline int get_use_count() { return m_use_count; }

  inline void dispose() { delete m_ptr; }

  inline void destroy() { delete this; }

  void release() {
    if (--m_use_count == 0) {
      dispose();
      if (--m_weak_count == 0) {
        destroy();
      }
    }
  }

  void weak_release() {
    if (--m_weak_count == 0) {
      destroy();
    }
  }

private:
  // friend class ThreadUnsafeSharedPtr;
  // friend class ThreadUnsafeWeakPtr;
  int m_use_count;
  int m_weak_count;
  Tp *m_ptr;
};

// todo: operator->和operator *
template <typename T> class ThreadUnsafeSharedPtr {

public:
  constexpr ThreadUnsafeSharedPtr() : m_ptr{nullptr}, m_refcount{nullptr} {}

  constexpr ThreadUnsafeSharedPtr(nullptr_t) noexcept
      : ThreadUnsafeSharedPtr() {}

  template <typename Yp>
  ThreadUnsafeSharedPtr(Yp *ptr)
      : m_ptr{ptr}, m_refcount{new shared_weak_count<Yp>(ptr)} {}

  ThreadUnsafeSharedPtr(const ThreadUnsafeWeakPtr<T> &r) noexcept
      : m_refcount{r.m_weakcount} {
    if (m_refcount == nullptr) [[unlikely]] {
      m_ptr = nullptr;
    } else {
      /**
       * 如果lock失败, 返回的ThreadUnsafeSharedPtr应为初始状态
       * 即m_ptr = nullptr, m_refcount = nullptr
       */
      bool lockSucc = m_refcount->get_use_count() > 0;
      if (lockSucc) [[likely]] {
        m_ptr = r.m_ptr;
        m_refcount->add_ref_copy(); // 如果能够lock, use_count引用+1
      } else {
        m_ptr = nullptr;
        m_refcount = nullptr;
      }
    }
  }

  ThreadUnsafeSharedPtr(const ThreadUnsafeSharedPtr &r)
      : m_ptr{r.m_ptr}, m_refcount{r.m_refcount} {
    if (m_refcount != nullptr) {
      m_refcount->add_ref_copy();
    }
  }

  ThreadUnsafeSharedPtr(ThreadUnsafeSharedPtr &&r)
      : m_ptr{r.m_ptr}, m_refcount{r.m_refcount} {
    r.m_ptr = nullptr;
    r.m_refcount = nullptr;
  }

  ThreadUnsafeSharedPtr &operator=(const ThreadUnsafeSharedPtr &r) {
    m_ptr = r.m_ptr;
    shared_weak_count<T> *tmp = r.m_refcount;
    if (tmp != m_refcount) {
      if (tmp != nullptr) {
        tmp->add_ref_copy();
      }

      if (m_refcount != nullptr) {
        m_refcount->release();
      }

      m_refcount = tmp;
    }
    return *this;
  }

  ThreadUnsafeSharedPtr &operator=(ThreadUnsafeSharedPtr &&r) {
    m_ptr = r.m_ptr;
    // 如果this对象不为nullptr, 则release
    if (m_refcount != nullptr) {
      m_refcount->release();
    }
    m_refcount = r.m_refcount;
    r.m_ptr = nullptr;
    r.m_refcount = nullptr;
    return *this;
  }

  T *operator->() const noexcept { return m_ptr; }

  T *get() const noexcept { return m_ptr; }

  T &operator*() const noexcept { return *m_ptr; }

  int use_count() const noexcept {
    return m_refcount ? m_refcount->get_use_count() : 0;
  }

  explicit operator bool() const noexcept { return m_ptr != nullptr; }

  ~ThreadUnsafeSharedPtr() {
    if (m_refcount != nullptr) {
      m_refcount->release();
    }
  }

private:
  friend class ThreadUnsafeWeakPtr<T>;
  T *m_ptr;
  shared_weak_count<T> *m_refcount;
};

template <typename T> class ThreadUnsafeWeakPtr {
public:
  constexpr ThreadUnsafeWeakPtr() : m_ptr{nullptr}, m_weakcount{nullptr} {}

  constexpr ThreadUnsafeWeakPtr(nullptr_t) noexcept : ThreadUnsafeWeakPtr() {}

  ThreadUnsafeWeakPtr(const ThreadUnsafeSharedPtr<T> &r) noexcept
      : m_ptr{r.m_ptr}, m_weakcount{r.m_refcount} {
    if (m_weakcount != nullptr) {
      m_weakcount->add_weak_copy();
    }
  }

  ThreadUnsafeWeakPtr(const ThreadUnsafeWeakPtr &r)
      : m_ptr{r.m_ptr}, m_weakcount{r.m_weakcount} {
    if (m_weakcount != nullptr) {
      m_weakcount->add_weak_copy();
    }
  }

  ThreadUnsafeWeakPtr(ThreadUnsafeWeakPtr &&r) noexcept
      : m_ptr{r.m_ptr}, m_weakcount{r.m_weakcount} {
    r.m_ptr = nullptr;
    r.m_weakcount = nullptr;
  }

  ThreadUnsafeWeakPtr &operator=(const ThreadUnsafeWeakPtr &r) noexcept {
    m_ptr = r.m_ptr;
    shared_weak_count<T> *tmp = r.m_weakcount;
    // 如果r对象不为null, 则增加其weak_count
    if (tmp != nullptr) {
      tmp->add_weak_copy();
    }

    // 如果this对象不为null, 则需要减少其weak_count
    if (m_weakcount != nullptr) {
      m_weakcount->weak_release();
    }
    m_weakcount = tmp;
    return *this;
  }

  ThreadUnsafeWeakPtr &operator=(ThreadUnsafeWeakPtr &&r) noexcept {
    m_ptr = r.m_ptr;
    if (m_weakcount != nullptr) {
      m_weakcount->weak_release(); // 更新this对象的weakcount状态
    }
    m_weakcount = r.m_weakcount;
    r.m_ptr = nullptr;
    r.m_weakcount = nullptr;
    return *this;
  }

  ~ThreadUnsafeWeakPtr() {
    if (m_weakcount != nullptr) {
      m_weakcount->weak_release();
    }
  }

  ThreadUnsafeSharedPtr<T> lock() const noexcept {
    return ThreadUnsafeSharedPtr<T>(*this);
  }

  int use_count() const noexcept {
    return m_weakcount != nullptr ? m_weakcount->get_use_count() : 0;
  }

private:
  friend class ThreadUnsafeSharedPtr<T>;
  T *m_ptr;
  shared_weak_count<T> *m_weakcount;
};

template <typename Tp>
inline bool operator==(const ThreadUnsafeSharedPtr<Tp> &a, nullptr_t) noexcept {
  return !a;
}
}; // namespace TinyNet

你可能感兴趣的:([笔记],c++,开发语言)