目录
前边说过可以通过使用weak_ptr来解决shared_ptr的相互引用问题。本篇我们会从weak_ptr的构成和内纯分布来深入了解如何解决的。
weak_ptr一般都会和shared_ptr一起使用。weak_ptr的结构只有一个变量_Rep,较为简单,所以我们来看两者结合的shared_ptr。
1.模拟实现加了weak_ptr后的shared_ptr:
1.1代码模拟简单实现:
class Object
{
private:
int value;
public:
Object(int x = 0) :value(x) {};
~Object() {};
}
};
template<class _Ty>
class RefCnt
{
public:
_Ty * _Ptr
std::atomic_int _Uses;
std::atomic_int _Weaks;
public:
RefCnt(_Ty* p ) :mptr(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 // thread;
{
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(p);
}
}
~my_shared_ptr()
{
if (this->_Ptr != nullptr && --this->Rep->_Uses == 0)
{
mDeletor(_Ptr);
if (-- this->_Rep->_Weaks == 0)
{
delete _Rep;
}
}
_Ptr = nullptr;
_Rep = nullptr;
}
class my_weak_ptr
{
private:
RefCnt<_Ty>* _Rep;
public:
my_weak_ptr() {}
my_weak_ptr(const my_weak_ptr& _Other)
{
_Rep = _Other._Rep;
if (_Rep != nullptr)
{
_Rep->_Incwref();
}
}
}
1.2内存分布如图:
int main()
{
my_shared_ptr<Object>op1(new Object(10));
return 0;
}
此时的内存分布如图,op1和RefCnt都指向Object对象,此时的删除是关键。
删除的设置也很巧妙:
~my_shared_ptr()
{
if (this->_Ptr != nullptr && --this->Rep->_Uses == 0)
{
mDeletor(_Ptr);
if (-- this->_Rep->_Weaks == 0)
{
delete _Rep;
}
}
_Ptr = nullptr;
_Rep = nullptr;
}
在上边RefCnt结构中存有_Uses和_Weaks。当_Uses=0时,析构op1,;当_Weaks=0时,析构RefCnt结构。
2.拷贝构造和赋值语句
weak_ptr和shared_ptr的拷贝构造和赋值语句原理相同。只增加_Uses的值,但在赋值语句时,判断this指针所指对象时,要考虑_weaks的值,当Weaks的值为1,就会析构RefCnt结构。简单来说,就是强引用销毁时,_Uses和weaks都要-1,弱引用销毁时,只有_Weaks-1.
要想改变_Weaks的值,只能通过定义weak_ptr指针管理的对象,如weak_ptr<object>op2(new (Object(10))).
my_shared_ptr(const my_shared_ptr& _Y) :_Ptr(_Y._Ptr),_Rep(_Y._Rep)
{
if (_Ptr != nullptr)
{
_Rep->_Incref();
}
}
my_shared_ptr& operator=(const my_shared_ptr& _Y) //
{
if (this == &_Y || this->_Ptr == _Y._Ptr) return *this;
if (_Ptr != NULL && --_Rep->_Uses == 0)
{
mDeletor(_Ptr);
if (--_Rep->_Weaks == 0)
{
delete _Rep;
}
}
_Ptr = _Y._Ptr;
_Rep = _Y._Rep
if (_Rep != nullptr)
{
_Rep->_Uses += 1;
}
return *this;
}
3.解决shared_ptr的相互引用:
weak_ptr的解决方法也很简单,把引用的shared_ptr换成weak_ptr即可。
class Child;
class Parent
{
public:
weak_ptr<Child>child;
Parent() { cout << "Create Parent" << endl; }
~Parent() { cout << "Destory Parent" << endl; }
void hi() { cout << "hello" << endl; }
};
class Child
{
public:
weak_ptr<Parent>parent;
Child() { cout << "Create Child" << endl; }
~Child() { cout << "Destory Child" << endl; }
};
int main()
{
shared_ptr<Parent>p = make_shared<Parent>();
shared_ptr<Child>c = make_shared<Child>();
p->child = c;
c->parent = p;
p->hi();
return 0;
}
所以内存分布如图:
这时只需要记着强引用销毁时,_Uses和weaks都要-1,弱引用销毁时,只有_Weaks-1.这边的释放过程特别重要,应反复琢磨。
运行结果:
解决了shared_ptr互相引用不能释放的问题。