shared_ptr and weak_ptr

shared_ptr

Reference from https://www.jianshu.com/p/b6ac02d406a0

shared_ The PTR class does almost nothing. It inherits__ shared_ptr, __shared_ptr has a type of__ shared_ Member of type count_ M_refcount, __shared_count has an internal type of_ Sp_counted_base *_ M_ Members of PI_ Sp_counted_base is the whole shared_ The core of PTR function, through_ Sp_counted_base controls the reference count to manage managed memory, as can be seen from the figure_ Sp_ counted_ The pointer of managed memory is not held in base. Here__ shared_ The member inside count is actually a member inherited from_ Sp_counted_base_ Sp_counted_ptr type_ Sp_counted_ptr type holds a pointer to managed memory internally_ M_ptr, _M_pi is a_ Sp_counted_base base class object pointer to_ Sp_counted_ptr subclass object memory, so_ M_ Inside the PI, you can control the reference count and release the managed memory at last.

Here called_ M_ PI is the management object, which is internal_ M_ptr is a managed object, which manages multiple shared of the same managed object_ PTR internally shares a management object (_M_pi), where there are multiple shared objects_ PTR may be through the first shared_ptr is copied or moved, and there are two member variables in the management object_ M_use_count and_ M_weak_count, _M_use_count refers to the reference count of managed objects. It controls when managed objects are destructed and released. There are probably N shared objects_ The reference count of the copy of PTR is N. when the reference count is 0, the destructor of the managed object is called and the memory is released_ M_weak_count refers to the reference count of the management object. The management object is also a memory pointer, which is the first shared during initialization_ PTR comes from new, and it also needs to delete in the end, so it is used_ M_weak_count to control when the management object is destructed. We usually use weak_ptr actually holds the pointer of this management object, when weak_ Reference count of management object when PTR copy_ M_ weak_ The count will increase when_ M_ weak_ When count is 0, the management object_ M_ PI will destruct and free memory.

class shared_ptr

template <typename _Tp> class shared_ptr : public __shared_ptr<_Tp>

Member function

template <typename _Tp1>
shared_ptr &operator=(const shared_ptr<_Tp1> &__r) noexcept {
  this->__shared_ptr<_Tp>::operator=(__r);
  return *this;
}

class __shared_ptr

  template <typename _Tp, _Lock_policy _Lp> class __shared_ptr

Member variable

_Tp *_M_ptr;                     // Contained pointer.
__shared_count<_Lp> _M_refcount; // Reference counter.

Member function

   // Overload assignment operator 
   __shared_ptr &operator=(const __shared_ptr &) noexcept = default;

   template <typename _Tp1>
    __shared_ptr &operator=(const __shared_ptr<_Tp1, _Lp> &__r) noexcept {
      _M_ptr = __r._M_ptr;
      _M_refcount = __r._M_refcount; // __shared_count::op= doesn't throw
      return *this;
    }


  // Constructor
   template <typename _Tp1>
    explicit __shared_ptr(_Tp1 *__p) : _M_ptr(__p), _M_refcount(__p) {
      __glibcxx_function_requires(
          _ConvertibleConcept<_Tp1 *, _Tp *>) static_assert(sizeof(_Tp1) > 0,
                                                            "incomplete type");
      __enable_shared_from_this_helper(_M_refcount, __p, __p);
    }

	// Destructor
    ~__shared_ptr() = default;

class __shared_count

Member variable

_Sp_counted_base<_Lp> *_M_pi;//_ M_pi is a_ Sp_counted_base base class object pointer to_ Sp_counted_ptr subclass object memory, so_ M_ Inside the PI, you can control the reference count and release the managed memory at last.

Member function

   // Constructor
  template <typename _Ptr> explicit __shared_count(_Ptr __p) : _M_pi(0) {
      __try {
        _M_pi = new _Sp_counted_ptr<_Ptr, _Lp>(__p); //   _ M_pi pointing_ Sp_counted_ptr subclass object memory
      }
      __catch(...) {
        delete __p;
        __throw_exception_again;
      }
    }

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


   // Overload assignment operator
   __shared_count &operator=(const __shared_count &__r) noexcept {
      _Sp_counted_base<_Lp> *__tmp = __r._M_pi;
      if (__tmp != _M_pi) {
        if (__tmp != 0)
          __tmp->_M_add_ref_copy();
        if (_M_pi != 0)
          _M_pi->_M_release();
        _M_pi = __tmp;
      }
      return *this;
    }


    explicit operator bool() const // never throws
    {
      return _M_ptr == 0 ? false : true;
    }

class _Sp_counted_base

template <_Lock_policy _Lp = __default_lock_policy>
class _Sp_counted_base : public _Mutex_base<_Lp>

Member variable

private:
  _Atomic_word _M_use_count;  // #shared
  _Atomic_word _M_weak_count; // #weak + (#shared != 0)

Member function

 _Sp_counted_base() noexcept : _M_use_count(1), _M_weak_count(1) {}
//Note that when shared_ptr copy or move_ M_weak_count will not increase. It represents the count of management objects. Only when__ M_ use_ When count is 0_ M_weak_count will be reduced by 1. In addition_ M_ weak_ The value of count is determined by weak_ptr controlled.

virtual ~_Sp_counted_base() noexcept {}


 void _M_add_ref_copy() {
      __gnu_cxx::__atomic_add_dispatch(&_M_use_count, 1);
    }


 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) {
          _GLIBCXX_READ_MEM_BARRIER;
          _GLIBCXX_WRITE_MEM_BARRIER;
        }

        // 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()
          _GLIBCXX_READ_MEM_BARRIER;
          _GLIBCXX_WRITE_MEM_BARRIER;
        }
        _M_destroy();
      }
    }

class _Sp_counted_ptr

template <typename _Ptr, _Lock_policy _Lp>
class _Sp_counted_ptr final : public _Sp_counted_base<_Lp>

Member variable

protected:
  _Ptr _M_ptr; // Pointer to managed memory

Member function

explicit _Sp_counted_ptr(_Ptr __p) : _M_ptr(__p) {}


 virtual void _M_dispose() noexcept { delete _M_ptr; }

 virtual void _M_destroy() noexcept { delete this; }

weak_ptr

Reference from https://www.jianshu.com/p/b6ac02d406a0

Note that when shared_ptr copy or move_ M_weak_count will not increase. It represents the count of management objects. Only when__ M_ use_ When count is 0_ M_weak_count will be reduced by 1. In addition_ M_ weak_ The value of count is determined by weak_ptr controlled.

weak_ptr internal and shared_ptr internally holds the same management object pointer, i.e_ Sp_ counted_ Pointer to base, when weak_ When PTR is assigned, copied and destructed_ Sp_counted_base internal_ M_weak_count will be added or subtracted accordingly. When_ M_ weak_ When count is 0, it means that the managed object is no longer needed to control the managed object. Call_ M_ delete this of destroy() to free the memory of the management object.

weak_ptr does not prolong the life cycle of the object pointed to by the native pointer. In fact, it is weak_ptr also has no constructor of native pointer, which can only be used by shared_ptr or weak_ptr is constructed. It is a pointer for the purpose of extending the life cycle.

class weak_ptr

template <typename _Tp> class weak_ptr : public __weak_ptr<_Tp>

Member function

template <typename _Tp1>
weak_ptr &operator=(const weak_ptr<_Tp1> &__r) noexcept {
  this->__weak_ptr<_Tp>::operator=(__r);
  return *this;
}

 template <typename _Tp1,
              typename = typename std::enable_if<
                  std::is_convertible<_Tp1 *, _Tp *>::value>::type>
    weak_ptr(const weak_ptr<_Tp1> &__r) noexcept : __weak_ptr<_Tp>(__r) {}


// Used to extend the life cycle
    shared_ptr<_Tp> lock() const noexcept {
#ifdef __GTHREADS
      if (this->expired())
        return shared_ptr<_Tp>();

      __try {
        return shared_ptr<_Tp>(*this);
      }
      __catch(const bad_weak_ptr &) { return shared_ptr<_Tp>(); }
#else
      return this->expired() ? shared_ptr<_Tp>() : shared_ptr<_Tp>(*this);
#endif
    } 

class __weak_ptr

template <typename _Tp, _Lock_policy _Lp> class __weak_ptr

Member variable

_Tp *_M_ptr;                   // Contained pointer.
__weak_count<_Lp> _M_refcount; // Reference counter.

Member function

  template <typename _Tp1,
              typename = typename std::enable_if<
                  std::is_convertible<_Tp1 *, _Tp *>::value>::type>
    __weak_ptr(const __shared_ptr<_Tp1, _Lp> &__r) noexcept
        : _M_ptr(__r._M_ptr), _M_refcount(__r._M_refcount) {}


template <typename _Tp1>
__weak_ptr &operator=(const __weak_ptr<_Tp1, _Lp> &__r) noexcept {
  _M_ptr = __r.lock().get();
  _M_refcount = __r._M_refcount;
  return *this;
}

__weak_ptr(const __weak_ptr &) noexcept = default;

 ~__weak_ptr() = default;

bool expired() const noexcept {
  return _M_refcount._M_get_use_count() == 0;
}

class __weak_count

template <_Lock_policy _Lp> class __weak_count

Member variable

_Sp_counted_base<_Lp> *_M_pi;

Member function

__weak_count(const __weak_count<_Lp> &__r) noexcept : _M_pi(__r._M_pi) {
  if (_M_pi != 0)
    _M_pi->_M_weak_add_ref();
}

__weak_count<_Lp> &operator=(const __weak_count<_Lp> &__r) noexcept {
      _Sp_counted_base<_Lp> *__tmp = __r._M_pi;
      if (__tmp != 0)
        __tmp->_M_weak_add_ref();
      if (_M_pi != 0)
        _M_pi->_M_weak_release();
      _M_pi = __tmp;
      return *this;
 }

 ~__weak_count() noexcept {
      if (_M_pi != 0)
        _M_pi->_M_weak_release();
 }

Keywords: C++ STL

Added by minou on Mon, 31 Jan 2022 05:14:05 +0200