一、weak_ptr的诞生
1.为什么会有weak_ptr,看下面例子
class b;
class a
{
public:
shared_ptr<b> _b;
~a() {
cout << "destroy a" << endl;
}
void hi()const
{
cout << "hi" << endl;
}
};
class b
{
public:
shared_ptr<a> _a;
~b()
{
cout << "destory b" << endl;
}
};
int main()
{
shared_ptr<a>pa = make_shared<a>();
shared_ptr<b>pb = make_shared<b>();
pa->_b = pb;
pb->_a = pa;
pb->_a->hi();
return 0;
}
上述代码的运行结果,只打印出“hi”,说明a和b的析构函数并没有调用到。这是因为a和b的对象内部,具有各自指向对方的shared_ptr,并且a和b的引用计数都是2.当程序退出时,引用计数减为1,对象并没有被析构掉。可以简单理解如下图:
运行结果如下
二、weak_ptr是什么?
weak_ptr是为了配合shared_ptr而引入的一种智能指针,它指向一个由shared_ptr管理的对象而不影响所指对象的生命周期,即就是将一个weak_ptr绑定到shared_ptr不会改变shared_ptr的引用计数。不论是否有用weak_ptr指向一旦最后一个指向对象的shared_ptr被销毁,对象就会是释放。从这个角度看,weak_ptr更像是一个shared_ptr的助手,weak_ptr并不拥有对对象的管辖权,weak_ptr指向shared_ptr的目标也不会增加计数器值。
1.创建weak_ptr
当我们创建weak_ptr时,需要用一个shared_ptr实例来初始化weak_ptr,由于是弱共享,weak_ptr的创建并不会影响shared_ptr的引用计数值。
int main()
{
shared_ptr<int>a1(new int(5));
cout << a1.use_count() << endl;
weak_ptr<int>a2(a1);
cout << a1.use_count() << endl;
return 0;
}
运行结果如下
2.如何判断weak_ptr指向对象是否存在
既然weak_ptr并不改变其所共享的shared_ptr实例的引用计数,那就可能存在weak_ptr指向对象被释放掉这种情况。这时,我们就不能使用weak_ptr直接的访问对象,C++通过lock()函数实现该功能。
如果对象存在,loick()函数返回一个指向共享对象的shared_ptr,否则返回一个空shared_ptr。
class Object
{
private:
int value;
public:
Object(int x = 0) :value(x)
{
cout << "Object Create" << endl;
}
~Object() { cout << "Object Destroy" << endl; }
int GetValue()const
{
return value;
}
};
int main()
{
shared_ptr<Object>pa(new Object(10));
weak_ptr<Object>pb(pa);
if (shared_ptr<Object>pc = pb.lock())
{
cout << pc->GetValue() << endl;
}
else
{
cout << pb.expired() << endl;
cout << "pb 引用对象为空" << endl;
}
return 0;
}
3.weak_ptr的使用
weak_ptr没有重载operator->和operator *操作符,无法访问对象,可以使用 lock()访问原始对象;
class b;
class a
{
public:
weak_ptr<b> _b;
~a() {
cout << "destroy a" << endl;
}
void hi()const
{
cout << "hi" << endl;
}
};
class b
{
public:
weak_ptr<a> _a;
~b()
{
cout << "destory b" << endl;
}
};
int main()
{
shared_ptr<a>pa = make_shared<a>();
shared_ptr<b>pb = make_shared<b>();
pa->_b = pb;
pb->_a = pa;
if (!(pb->_a.expired()))
{
pb->_a.lock()->hi();
}
return 0;
}
运行结果
三、仿写weak_ptr
#ifndef MY_WEAK_PTR
#define MY_WEAK_PTR
#include<atomic>
template<class _Ty>
class MyDeletor
{
public:
MyDeletor() {}
void operator() {_Ty* ptr}const
{
if (ptr != nullptr)
{
delete ptr;
}
}
};
template<class _Ty>
class MyDeletor<_Ty[]>
{
public:
MyDeletor() = default;
void operator() { _Ty* ptr }const
{
if (ptr != nullptr)
{
delete []ptr;
}
}
};
template <class _Ty>
class RefCnt
{
public:
_Ty* _Ptr;
std::atomic_int _Uses;
std::atomic_int _Weaks;
public:
RefCnt(_Ty* p) :_Ptr(p), _Uses(1), _Weaks(1) {}
~RefCnt() {}
void _Incref() { _Uses += 1; }
void _Incwref() { _Weaks += 1; }
};
template<class _Ty,class _Dx=MyDeletor<_Ty>>
class my_shared_ptr
{
private:
_Ty* _Ptr;
RefCnt<_Ty>* _Rep;
_Dx _mDeletor;
public:
my_shared_ptr(_Ty* p = nullptr) :_Ptr(nullptr), _Rep(nullptr)
{
if (p != nullptr)
{
_Ptr = p;
_Rep = new RefCnt<_Ty>(p);
}
}
my_shared_ptr(const my_shared_ptr& _Y) :_Ptr(_Y._Ptr), _Rep(_Y._Rep)
{
if (_Rep != nullptr)
{
_Rep->_Incref();
}
}
my_shared_ptr(my_shared_ptr&& other):_Ptr(other._Ptr),_Rep(other._Rep)
{
other._Ptr = nullptr;
other._Rep = nullptr;
}
my_shared_ptr& operator =(const my_shared_ptr& r)
{
if (this == &r || this->_Ptr == r._Ptr)return *this;
if (_Ptr != nullptr && --_Rep->_Uses == 0)
{
_mDeletor(_Ptr);
if (--_Rep->_Weaks == 0)
{
delete _Rep;
}
}
_Ptr = r._Ptr;
_Rep = r._Rep;
if (_Ptr != nullptr)
{
_Rep->_Incref();
}
return *this;
}
my_shared_ptr& operator =(my_shared_ptr&& other)
{
if (this == &other)return *this;
if (this->_Ptr != nullptr && other->_Ptr != nullptr && _Ptr == other->_Ptr)
{
this->_Rep->_Uses -= 1;
other->_Ptr = nullptr;
other->_Rep = nullptr;
return *this;
}
if (_Ptr != nullptr && --_Rep->_Uses == 0)
{
_mDeletor(_Ptr);
if (--_Rep->_Weaks == 0)
{
delete _Rep;
}
}
_Ptr = other._Ptr;
_Rep = other._Rep;
other._Ptr = nullptr;
other._Rep = nullptr;
return *this;
}
~my_shared_ptr()
{
if (_Rep != nullptr && --_Rep->_Uses == 0)
{
_mDeletor(_Ptr);
if (--_Rep->_Weaks == 0)
{
delete _Rep;
}
}
_Ptr = nullptr;
_Rep = nullptr;
}
_Ty* get()const { return _Ptr; }
_Ty& operator*()const { return *get(); }
_Ty* operator ->() const { return get(); }
size_t use_count()const
{
if (_Rep == nullptr)return 0;
return _Rep->_Uses;
}
void swap(my_shared_ptr& r)
{
std::swap(_Ptr, r._Ptr);
std::swap(_Rep, r._Rep);
}
operator bool()const { return _Ptr != nullptr; }
};
template <class _Ty>
class my_weak_ptr
{
private:
RefCnt<_Ty>* _Rep;
public:
my_weak_ptr() :_Rep(nullptr) {}
my_weak_ptr(const my_weak_ptr<_Ty>& other) :_Rep(other._Rep)
{
if (_Rep != nullptr)
{
_Rep->_Incwref();
}
}
my_weak_ptr(const my_weak_ptr& other) :_Rep(other._Rep)
{
if (_Rep != nullptr)
{
_Rep->_Incwref();
}
}
my_weak_ptr(my_weak_ptr&& other) :_Rep(other._Rep)
{
other._Rep = nullptr;
}
my_weak_ptr& operator =(const my_weak_ptr& other)
{
if (this == &other || this->_Rep == other._Rep)return *this;
if (this->_Rep != nullptr && --_Rep->_Weaks == 0)
{
delete _Rep;
}
_Rep = other->_Rep;
if (_Rep != nullptr)
{
_Rep->_Incwref();
}
return *this;
}
my_weak_ptr& operator=(my_weak_ptr&& other)
{
if (this == &other)return *this;
if (this->_Rep != nullptr && other._Rep != nullptr && _Rep == other._Rep)
{
this->_Rep->_Weaks -= 1;
other._Rep = nullptr;
return *this;
}
if (_Rep != nullptr && --_Rep->_Weaks == 0)
{
delete _Rep;
}
_Rep = other._Rep;
other._Rep = nullptr;
return *this;
}
my_weak_ptr& operator(const my_shared_ptr<_Ty>& other)
{
if (_Rep != nullptr && --_Rep->Weaks == 0)
{
delete _Rep;
}
_Rep = other->_Rep;
if (_Rep != nullptr)
{
_Rep->Incwref();
}
return *this;
}
my_weak_ptr& operator =(my_shared_ptr<_Ty>&& other) = delete;
~my_weak_ptr()
{
if (_Rep != nullptr && --_Rep->_Weaks == 0)
{
delete _Rep;
}
_Rep = nullptr;
}
bool expired()const
{
return this->_Rep->_Uses == 0;
}
my_shared_ptr<_Ty>lock()const
{
my_shared_ptr<_Ty>_Ret;
_Ret._Ptr = _Rep->_Ptr;
_Ret._Rep = _Rep;
_Ret._Rep->_Incref;
}
};