[STL] std::shared_ptr笔记
std::shared_ptr 简易uml(只简单包含member variable&重要member function)
初始化以及引起引用计数变化的原因
这里暂时省略了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
的情况包括:
- std::shared_ptr的复制构造:
_M_use_count
=>_M_use_count + 1
- 复制拷贝:
_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;
}
- 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;
}
调用栈为:
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 this
再delete _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 <cstddef>
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<Tp>;
// friend class ThreadUnsafeWeakPtr<Tp>;
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