1个简单的 引用计数智能指针
本代码取自陈硕的 github 仓库
https://github.com/chenshuo/recipes/blob/master/basic/counted_ptr.h
(1) Ctor: 默认RCSP是空 RCSP: 目标对象和RC 指针均为空 => 还没产生 RC, 而不是 RC = 0
(2) Copy Ctor: 若右侧RCSP的RC指针非空
, 则 RC(原子)加1
(3) Move Ctor: 控制权转交, 源 RCSP 2个指针均置空
(4) Assignment: 调 swap(rhs)
, 交换两者的内容(2个指针) => 若1侧为默认RCSP, 交换后, 另一侧变为默认RCSP
(5) Dtor: 调 reset()
, 若 RC 指针非空, 则 RC(原子)减1
, 若减为0, 则 delete 目标对象和RC 内存
#pragma once
// A simple reference counted smart pointer.
// make use of GCC atomic builtins and C++ move semantics
template<typename T>
class counted_ptr
{
private:
T* ptr_; // 目标对象指针
int* count_; // RC 动态内存指针
public:
// (1) Ctor: 若 RCSP 所接管的裸指针为空, RC指针置空;
// => `默认 RCSP 是 空 RCSP: 目标对象和RC 指针均为空 => 还没产生 RC, 而不是 RC = 0`
// else, RC指针指向新分配的空间, RC初值为1
counted_ptr(T* p = nullptr)
: ptr_(p),
count_(p ? new int(1) : nullptr)
{ }
// (2) Copy Ctor: 若右侧RCSP的RC指针非空, 则 RC(原子)加1
counted_ptr(const counted_ptr& rhs) noexcept
: ptr_(rhs.ptr_),
count_(rhs.count_)
{
if (count_)
__atomic_fetch_add(count_, 1, __ATOMIC_SEQ_CST);
}
// (3) Move Ctor: 控制权转交, 源 RCSP 2个指针均置空
counted_ptr(counted_ptr&& rhs) noexcept
: ptr_(rhs.ptr_),
count_(rhs.count_)
{
rhs.ptr_ = nullptr;
rhs.count_ = nullptr;
}
// (4) Assignment: 调 swap(rhs)
counted_ptr&
operator=(counted_ptr rhs)
{
swap(rhs);
return *this;
}
// 交换两者的内容(2个指针) => `若1侧为默认RCSP, 交换后, 另一侧变为默认RCSP`
void swap(counted_ptr& rhs) noexcept
{
T* tp = ptr_;
ptr_ = rhs.ptr_;
rhs.ptr_ = tp;
int* tc = count_;
count_ = rhs.count_;
rhs.count_ = tc;
}
// (5) Dtor: 调 reset()
~counted_ptr()
{
reset();
}
// 若 RC 指针非空, 则 RC(原子)减1, 若减为0, 则 delete 目标对象和RC 内存
void reset()
{
static_assert(sizeof(T) > 0, "T must be complete type");
if (count_)
{
if (__atomic_sub_fetch(count_, 1, __ATOMIC_SEQ_CST) == 0)
{
delete ptr_;
delete count_;
}
ptr_ = nullptr;
count_ = nullptr;
}
}
// (6) 获取内部裸指针
T*
get() const noexcept
{
return ptr_;
}
// (7) 获取内部 RC: (原子)load
int
use_count() const noexcept
{
return count_ ? __atomic_load_n(count_, __ATOMIC_SEQ_CST) : 0;
}
T*
operator->() const noexcept
{
return ptr_;
}
T&
operator*() const noexcept
{
return *ptr_;
}
};