一、环状引用

举个栗子:

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;
}

运行结果:
在这里插入图片描述
一个很明显的错误:那就是内存泄漏了,调用了构造却没有调用析构函数。这就是环状引用带来的问题。


二、环状引用内存结构

我们分步骤进行构建:
在这里插入图片描述

在这里插入图片描述
可以看到关系还是十分的复杂。其主要原因出在析构上。

三、解决方案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;
}

运行结果:
在这里插入图片描述
可以看到,所管理的对象在环形引用下也完成了资源的释放。成功解决了内存泄露的问题。我们通过构造和析构的过程对其进行分析。


四、weak_ptr环形引用结构图

(1)构造过程

在这里插入图片描述
在这里插入图片描述

(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
在这里插入图片描述

第二步:析构pa,_b
在这里插入图片描述
可以看到在使用了弱引用的环状引用已经可以解决内存泄露的问题。