一、环状引用
举个栗子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| #include <iostream> #include <memory>
class B; class A { public: shared_ptr<B> _b; A() { cout << "A()" << endl; } ~A() { cout << "~A()"<< endl; } };
class B { public: shared_ptr<A> _a; B() { cout << "B()" << endl; } ~B() { cout << "~B()" << endl; } };
void fun() { shared_ptr<A> pa = make_shared<A>(); shared_ptr<B> pb = make_shared<B>();
pa->_b = pb; pb->_a = pa; } int main() { fun(); return 0; }
|
运行结果:
![在这里插入图片描述](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)
一个很明显的错误:那就是内存泄漏了,调用了构造却没有调用析构函数。这就是环状引用带来的问题。
二、环状引用内存结构
我们分步骤进行构建:
![在这里插入图片描述](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)
![在这里插入图片描述](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)
可以看到关系还是十分的复杂。其主要原因出在析构上。
三、解决方案weak_ptr
为了使环状引用得到解决,使用weak_ptr便可以很好的处理这种情况。
下来看看weak_ptr是如何解决的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| class B; class A { public: weak_ptr<B> _b; A() { cout << "A()" << endl; } ~A() { cout << "~A()" << endl; } };
class B { public: weak_ptr<A> _a; B() { cout << "B()" << endl; } ~B() { cout << "~B()" << endl; } };
void fun2() { shared_ptr<A> pa = make_shared<A>(); shared_ptr<B> pb = make_shared<B>(); pa->_b = pb; pb->_a = pa; } int main() { fun2(); return 0; }
|
运行结果:
![在这里插入图片描述](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)
可以看到,所管理的对象在环形引用下也完成了资源的释放。成功解决了内存泄露的问题。我们通过构造和析构的过程对其进行分析。
四、weak_ptr环形引用结构图
(1)构造过程
![在这里插入图片描述](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)
![在这里插入图片描述](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)
(2)析构过程
shared_ptr析构函数:
1 2 3 4 5 6 7 8 9 10 11
| ~shared_ptr() { if (_Ref != NULL && --_Ref->_Users == 0) { _deleter(_Ptr); if (--_Ref->_Weaks == 0) { delete _Ref; } } }
|
weak_ptr析构函数:
1 2 3 4 5 6 7
| ~weak_ptr() { if (_Rp != NULL && --_Rp->_Weaks == 0) { delete _Rp; } }
|
第一步:析构pb,_a
![在这里插入图片描述](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)
第二步:析构pa,_b
![在这里插入图片描述](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)
可以看到在使用了弱引用的环状引用已经可以解决内存泄露的问题。