文章目录

weak_ptr概念

My_weak_ptr是一个模板派生类,My_Ptr_base是它的基类

  1. My_weak_ptr模板类没有自己的数据成员,而是只提供了一些供调用的接口;
  2. 只能使用 My_shared_ptr 和 My_weak_ptr 对象来构造 My_weak_ptr对象。
  3. My_weak_ptr对象的构造完成只能使_weaks的值加1 ;
  4. My_weak_ptr的生命期结束时,自动调用析构函数,析构函数中会调用计数器的My_Ref_count_base::_Decwref ()函数,weaks的引用计数减1,若_weaks计数为0,就会调用My_Ref_count_base::_Delete_this函数删除计数器对象,注意不能删除资源对象。
  5. 没有重载operator *,operator-> 函数
  6. 辅助函数:
  • reset 释放被管理对象的所有权。调用后*this不管理对象
  • swap 交换被管理对象,只能与其他weak_ptr对象交换。不调整引用计数
  • use_count() 返回管理该资源对象的shared_ptr指针对象的数量
  • expired() 检直被引用的资源对象是否已删除
  • Iock() 创建管理被引用的对象的shared_ptr,是线性安全的

My_Ptr_base 类

template<class T>
class My_Ptr_base {
public:
using element_type = T;

My_Ptr_base(const My_Ptr_base&) = delete;
My_Ptr_base& operator=(const My_Ptr_base&) = delete;

element_type* get() const {
return _Ptr;
}

long use_count() const {
return _Rep == nullptr ? 0 : _Rep->_use_count();
}

protected:
My_Ptr_base() = default;
~My_Ptr_base() = default;

// const My_Ptr_base* this
void Incref() const {
if (nullptr != _Rep) {
_Rep->_Incref();
}
}

void Inwcref() const {
if (nullptr != _Rep) {
_Rep->_Incwref();
}
}

void Decref() const {
if (nullptr != _Rep) {
_Rep->_Decref();
}
}

void Decwref() const {
if (nullptr != _Rep) {
_Rep->_Decwref();
}
}

void Ptr_base_Swap(My_Ptr_base& right) {
std::swap(_Ptr, right._Ptr);
std::swap(_Rep, right._Rep);
}

protected:
// 用shared_ptr构造shared_ptr
void _Copy_construct_from(const My_shared_ptr<T>& left) {
if (this == &left) {
return;
}
this->_Ptr = left._Ptr;
this->_Rep = left._Rep;
this->Incref();
}

// 用weak_ptr构造shared_ptr
void _Construct_from_weak(const My_weak_ptr<T>& left) {
if (this == &left) {
return;
}
// 如果_Uses为0了,资源对象就释放了,不能用weak_ptr构造shared_ptr
if (nullptr != left._Rep && left.use_count() > 0) {
this->_Ptr = left._Ptr;
this->_Rep = left._Rep;
this->Incref();
}
}

// 用weak_ptr和shared_ptr进行拷贝构造weak_ptr
// 因为weak_ptr可以通过weak_ptr和shared_ptr进行拷贝构造,所以这里形参用My_Ptr_base,可以接收weak_ptr和shared_ptr实参
void _Weak_Copy_construct_from(const My_Ptr_base<T>& left) {
if (this == &left) {
return;
}
// weak_ptr只关心引用计数器是否存活
if (nullptr != left._Rep) {
this->_Ptr = left._Ptr;
this->_Rep = left._Rep;
this->Inwcref();
}
}

// 移动构造的参数不要用const,否则不能修改参数的成员
void _Move_construct_from(My_Ptr_base<T>&& right) {
if (this == &right) {
return;
}
this->_Ptr = right._Ptr;
this->_Rep = right._Rep;
right._Ptr = nullptr;
right._Rep = nullptr;
}

template<class T>
friend class My_weak_ptr;

protected:
element_type* _Ptr{nullptr};
My_Ref_count_base* _Rep{ nullptr };
};

My_weak_ptr的拷贝构造和赋值

template<class T>
class My_weak_ptr : public My_Ptr_base<T> {
public:
My_weak_ptr() = default;
// My_weak_ptr(T* p) {} // 不允许通过资源创建weak_ptr
My_weak_ptr(const My_weak_ptr<T>& left) {
this->_Weak_Copy_construct_from(left);
}
My_weak_ptr(My_weak_ptr<T>&& right) {
this->_Move_construct_from(std::move(right)); // right为左值引用变量,本身是一个左值,需要再转换一次
}
My_weak_ptr(My_shared_ptr<T>& left) {
this->_Weak_Copy_construct_from(left);
}
My_weak_ptr(My_shared_ptr<T>&& right) = delete; // 不能把shared_ptr的资源转移给weak_ptr


My_weak_ptr& operator=(const My_weak_ptr<T>& left) {
My_weak_ptr(left).Swap(*this);
return *this;
}
My_weak_ptr& operator=(My_weak_ptr<T>&& right) {
My_weak_ptr(std::move(right)).Swap(*this);
return *this;
}
My_weak_ptr& operator=(const My_shared_ptr<T>& left) {
My_weak_ptr(left).Swap(*this);
return *this;
}
My_weak_ptr& operator=(My_shared_ptr<T>&& right) = delete; // 不能把shared_ptr的资源转移给weak_ptr

~My_weak_ptr() {
this->Decwref();
}

void Swap(My_weak_ptr& other) {
this->Ptr_base_Swap(other);
}

// 将this置空
void reset() {
My_weak_ptr().Ptr_base_Swap(*this);
}

bool expired() const {
return this->use_count() == 0; // My_Ptr_base::use_count()
}
};

lock方法

weak_ptr智能观察对象,如果资源存在,可以通过lock方法获得一个管理此资源的shared_ptr,如果不存在,则返回空对象,即不管理任何资源的shared_ptr

最简易的实现方式如下:

My_shared_ptr<T> lock() const {
My_shared_ptr<T> sp; // 空智能指针,不管理任何资源
sp._Construct_from_weak(*this);
return sp;
}

智能指针并不是线程安全的,比如智能指针的赋值拷贝,首先拷贝指向对象的指针,再使引用次数加减操作,虽然引用次数加减是原子操作,但是指针拷贝和引用次数两步操作并不是原子操作,线程不安全,需要手动加锁解锁

但是lock方法一定要保证线程安全,怕的就是先判断资源存在,准备将weak_ptr提升成shared_ptr时,资源又被释放了,此时再用已经释放的资源给lock方法即将返回的shared_ptr对象管理就会出问题

template<class T>
class My_Ptr_base {
protected:
// 用weak_ptr构造shared_ptr
void _Construct_from_weak(const My_weak_ptr<T>& left) {
if (this == &left) {
return;
}
// 如果_Uses为0了,资源对象就释放了,不能用weak_ptr构造shared_ptr
if (nullptr != left._Rep && left.Incref_nz()) {
this->_Ptr = left._Ptr;
this->_Rep = left._Rep;
}
}
};
class My_Ref_count_base {
public:
bool Incref_nz() {
int cnt = _Uses.load(); // load获取当前atomic类的计数值
while (cnt != 0) {
// cnt不为0,则有资源
if (_Uses.compare_exchange_weak(cnt, cnt + 1)) {
// compare_exchange_weak将_Uses原子值和第一个参数cnt相等,则用第一个参数cnt+1替换Uses_的原子值,返回true
// 否则将Uses_的原子值写入第一个参数cnt,返回false
return true;
}
}
return false;
}
};

如果线程A调用lock方法,将一个weak_ptr提升成shared_ptr,需要调用My_Ptr_base::_Construct_from_weak,然后执行My_Ref_count_base::Incref_nz增加Uses_引用计数,才能构造新的shared_ptr返回

如果说线程A执行Incref_nz时,获取Uses_的原子值是1,即cnt为1,资源存在,可以将weak_ptr提升成shared_ptr,于是进入while循环。即将执行if判断时,切换到线程B执行,最后一个shared_ptr释放,Uses_的原子值被修改为0,资源释放(此时weak_ptr提升shared_ptr失败)

此时切换回线程A执行,用cnt和Uses_的原子值比较发现不相等,就会把Uses_的原子值0写入cnt变量,返回false。此时cnt为0,退出while循环,返回false

这样就保证了Incref_nz能正确的将Uses_的原子值+1

完整代码

class My_Ref_count_base;

template<class T>
class My_Ref_count;

template<class Resource, class Dx>
class My_Ref_count_resource;

template<class T>
class My_Ref_base;

template<class T>
class My_shared_ptr;

template<class T>
class My_weak_ptr;

// 引用计数对象的基类
class My_Ref_count_base {
public:
// 派生类无法进行拷贝构造和赋值
My_Ref_count_base(const My_Ref_count_base&) = delete;
My_Ref_count_base& operator=(const My_Ref_count_base&) = delete;
virtual ~My_Ref_count_base() {}; // 虚析构,多态释放

void _Incref() { _Uses += 1; }
void _Incwref() { _Weaks += 1; }

bool Incref_nz() {
int cnt = _Uses.load();
while (cnt != 0) {
if (_Uses.compare_exchange_weak(cnt, cnt + 1)) {
return true;
}
}
return false;
}

void _Decwref() {
if (--_Weaks == 0) {
_Delete_this();
}
}

void _Decref() {
if (--_Uses == 0) {
// _Uses == 0,删除资源,并将_Weaks--
_Destroy();
_Decwref();
}
}

long _use_count() const {
return _Uses;
}

private:
virtual void _Destroy() = 0; // 删除资源对象
virtual void _Delete_this() = 0; // 删除引用计数器对象本身

std::atomic_int _Uses{ 1 };
std::atomic_int _Weaks{ 1 };

protected:
My_Ref_count_base() = default;
};

// 无删除器的引用计数类型
template<class T>
class My_Ref_count : public My_Ref_count_base{
public:
My_Ref_count(T* Px)
: My_Ref_count_base()
, _Ptr(Px)
{}
private:
// 删除资源对象
virtual void _Destroy() {
delete _Ptr; // 删除单个对象,而不是一组对象
}

// 删除引用计数器对象本身
virtual void _Delete_this() {
delete this;
}
private:
T* _Ptr;
};

template<class T>
class My_Ptr_base {
public:
using element_type = T;

My_Ptr_base(const My_Ptr_base&) = delete;
My_Ptr_base& operator=(const My_Ptr_base&) = delete;

element_type* get() const {
return _Ptr;
}

long use_count() const {
return _Rep == nullptr ? 0 : _Rep->_use_count();
}

protected:
My_Ptr_base() = default;
~My_Ptr_base() = default;

// const My_Ptr_base* this
void Incref() const {
if (nullptr != _Rep) {
_Rep->_Incref();
}
}

bool Incref_nz() const {
if (nullptr != _Rep) {
return _Rep->Incref_nz();
}
}

void Inwcref() const {
if (nullptr != _Rep) {
_Rep->_Incwref();
}
}

void Decref() const {
if (nullptr != _Rep) {
_Rep->_Decref();
}
}

void Decwref() const {
if (nullptr != _Rep) {
_Rep->_Decwref();
}
}

void Ptr_base_Swap(My_Ptr_base& right) {
std::swap(_Ptr, right._Ptr);
std::swap(_Rep, right._Rep);
}

protected:
// 用shared_ptr构造shared_ptr
void _Copy_construct_from(const My_shared_ptr<T>& left) {
if (this == &left) {
return;
}
this->_Ptr = left._Ptr;
this->_Rep = left._Rep;
this->Incref();
}

// 用weak_ptr构造shared_ptr
void _Construct_from_weak(const My_weak_ptr<T>& left) {
if (this == &left) {
return;
}
// 如果_Uses为0了,资源对象就释放了,不能用weak_ptr构造shared_ptr
if (nullptr != left._Rep && left.Incref_nz()) {
this->_Ptr = left._Ptr;
this->_Rep = left._Rep;
}
}

// 用weak_ptr和shared_ptr进行拷贝构造weak_ptr
// 因为weak_ptr可以通过weak_ptr和shared_ptr进行拷贝构造,所以这里形参用My_Ptr_base,可以接收weak_ptr和shared_ptr实参
void _Weak_Copy_construct_from(const My_Ptr_base<T>& left) {
if (this == &left) {
return;
}
// weak_ptr只关心引用计数器是否存活
if (nullptr != left._Rep) {
this->_Ptr = left._Ptr;
this->_Rep = left._Rep;
this->Inwcref();
}
}

// 移动构造的参数不要用const,否则不能修改参数的成员
void _Move_construct_from(My_Ptr_base<T>&& right) {
if (this == &right) {
return;
}
this->_Ptr = right._Ptr;
this->_Rep = right._Rep;
right._Ptr = nullptr;
right._Rep = nullptr;
}

template<class T>
friend class My_weak_ptr;

protected:
element_type* _Ptr{nullptr};
My_Ref_count_base* _Rep{ nullptr };
};

template<class T>
class My_shared_ptr : public My_Ptr_base<T> {
public:
explicit My_shared_ptr() = default;
// explicit My_shared_ptr(nullptr_t) = default;
explicit My_shared_ptr(T * Px) {
this->_Ptr = Px; // 资源
this->_Rep = new My_Ref_count<T>(Px); // 引用计数器
}

// My_shared_ptr的拷贝构造,就是需要将资源指针_Ptr和引用计数_Rep指针赋值,然后引用计数++
My_shared_ptr(const My_shared_ptr<T>& left) {
this->_Copy_construct_from(left);
}

My_shared_ptr(My_shared_ptr<T>&& right) {
this->_Move_construct_from(std::move(right)); // right为左值引用变量,本身是一个左值,需要再转换一次
}

My_shared_ptr(const My_weak_ptr<T>& left) {
this->_Copy_construct_from(left);
}

~My_shared_ptr() {
this->Decref();
}

My_shared_ptr& operator=(const My_shared_ptr<T>& left) {
My_shared_ptr(left).Swap(*this);
return *this;
}
My_shared_ptr& operator=(My_shared_ptr<T>&& right) {
My_shared_ptr(std::move(right)).Swap(*this);
return *this;
}


void Swap(My_shared_ptr& right) {
this->Ptr_base_Swap(right);
}
// 将当前对象置空
void reset() {
My_shared_ptr().Swap(*this); // swap后,this有了临时对象的资源,即被置空了,临时对象有了this的资源,出作用域被析构
}

void reset(T* Px) {
My_shared_ptr(Px).Swap(*this);
}

T& operator*() const { return *get(); }
T* operator->() const { return get(); }

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

private:
using My_Ptr_base<T>::get;
};


template<class T>
class My_weak_ptr : public My_Ptr_base<T> {
public:
My_weak_ptr() = default;
// My_weak_ptr(T* p) {} // 不允许通过资源创建weak_ptr
My_weak_ptr(const My_weak_ptr<T>& left) {
this->_Weak_Copy_construct_from(left);
}
My_weak_ptr(My_weak_ptr<T>&& right) {
this->_Move_construct_from(std::move(right)); // right为左值引用变量,本身是一个左值,需要再转换一次
}
My_weak_ptr(const My_shared_ptr<T>& left) {
this->_Weak_Copy_construct_from(left);
}
My_weak_ptr(My_shared_ptr<T>&& right) = delete; // 不能把shared_ptr的资源转移给weak_ptr


My_weak_ptr& operator=(const My_weak_ptr<T>& left) {
My_weak_ptr(left).Swap(*this);
return *this;
}
My_weak_ptr& operator=(My_weak_ptr<T>&& right) {
My_weak_ptr(std::move(right)).Swap(*this);
return *this;
}
My_weak_ptr& operator=(const My_shared_ptr<T>& left) {
My_weak_ptr(left).Swap(*this);
return *this;
}
My_weak_ptr& operator=(My_shared_ptr<T>&& right) = delete; // 不能把shared_ptr的资源转移给weak_ptr

~My_weak_ptr() {
this->Decwref();
}

void Swap(My_weak_ptr& other) {
this->Ptr_base_Swap(other);
}

// 将this置空
void reset() {
My_weak_ptr().Ptr_base_Swap(*this);
}

bool expired() const {
return this->use_count() == 0; // My_Ptr_base::use_count()
}

My_shared_ptr<T> lock() const {
My_shared_ptr<T> sp; // 空智能指针,不管理任何资源
sp._Construct_from_weak(*this);
return sp;
}
};