目录
一、为什么会有weak_ptr?
1、看一个例子
class Child;
class Parent {
public:
shared_ptr<Child> _child;
~Parent() {
cout << " Destroy Parent" << endl;
}
void hi()const {
cout << "hello" << endl;
}
};
class Child {
public:
shared_ptr<Parent> parent;
~Child() {
cout << " Bey child" << endl;
}
};
int main() {
shared_ptr<Parent>par = make_shared<Parent>();
shared_ptr<Child>pch = make_shared<Child>();
par->_child = pch;
pch->parent = par;
pch->parent->hi();
return 0;
}
到最后还是没有完成析构。
上面代码的运行结果,只打印出”Hello",而并没有打印出"Bye Parent"或"Bye Child",说明Parent和Child的析构函数并没有调用到。这是因为Parent和Child对象内部,具有各自指向对方的shared _ptr,加上parent和child这两个shared_ptr, 说明每个对象的引用计数都是2。当程序退出时,即使parent和child被销毁,也仅仅是导致引用计数变为了1,因此并未销毁Parent和Child对象。
为了解决类似这样的问题,C++11 引入了weak_ptr,来打破这种循环引用。
2.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 的目标也不会增加计数器的值,相反,weak_ptr 拥有一套不纳入计数器的指针系统。
3.weak_ ptr 如何使用?
接下来,我们来看看weak_ptr的简单用法。
1、如何创建weak_ ptr 实例
当我们创建一个weak_ptr 时,需要用一个shared_ptr实例来初始化weak_ptr,由于是弱共享, weak_ ptr的创建并不会影响shared_ptr 的引用计数值。
示例:
2、如何判断weak_ptr指向的对象是否存在
既然weak_ptr并不改变其所共享的shared_ptr实例的引用计数,那就可能存在weak_ptr指向的对象被释放掉这种情况。这时,我们就不能使用weak_ptr直接的访问对象。那么如何判断weak_ptr指向的对象存在呢?
c++提供lock函数来实现该功能。
如果对象存在,lock()函数返回一个指向共享对象的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>sp(new Object(10));
weak_ptr<Object>wp(sp);
if (shared_ptr<Object>pa = wp.lock()) {
cout << pa->GetValue() << endl;
}
else {
cout << wp.expired() << endl;//判断对象是否被销毁
cout << "wp 引用对象为空" << endl;
}
return 0;
}
3、weak_ptr的使用
weak_ptr没有重载operator->和operator *操作符号,无法访问对象,可以使用lock()访问原始对象;
class Child;
class Parent {
public:
weak_ptr<Child> _child;
~Parent() {
cout << " Destroy Parent" << endl;
}
void hi()const {
cout << "hello" << endl;
}
};
class Child {
public:
weak_ptr<Parent> parent;
~Child() {
cout << " Bey child" << endl;
}
};
int main() {
shared_ptr<Parent>par = make_shared<Parent>();
shared_ptr<Child>pch = make_shared<Child>();
par->_child = pch;
pch->parent = par;
if (!(pch->parent.expired())) {
pch->parent.lock()->hi();
}
return 0;
}
二、仿写std::weak_ptr
1、c++参考手册
2、代码
#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;
}
};
#endif