智能指针

C++ 11 提供了两种智能指针,区别在于管理底层指针的方式,shared_ptr 允许多个指针指向一个对象,unique_ptr 则独占所指向的对象。另外还定义了一个伴随类 weak_ptr,是一种弱引用,指向 shared_ptr 所管理的对象。

循环引用问题

shared_ptr 对象离开作用域后,其内部的引用计数器将减 1,若引用计数器为 0,则会自动释放内存

循环引用指两个对象互相使用其内部的 shared_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
31
32
33
34
35
36
37
38
39
#include <iostream>  
#include <memory>
using namespace std;
class B;

class A
{
public:
shared_ptr<B> a;
~A()
{
cout << "delete class A" << endl;
}
};

class B
{
public:
shared_ptr<A> b;
~B()
{
cout << "delete class B" << endl;
}
};

int main()
{
shared_ptr<A> a = make_shared<A>();
shared_ptr<B> b = make_shared<B>();
cout << "a use count:" << a.use_count() << endl;
cout << "b use count:" << b.use_count() << endl;

a->a = b;
b->b = a;
cout << "a use count:" << a.use_count() << endl;
cout << "b use count:" << b.use_count() << endl;

return 0;
}

运行结果:

1
2
3
4
a use count:1
b use count:1
a use count:2
b use count:2

在上面的例子中,当创建智能指针 ab 时,两个智能指针的引用计数器加 1,因此前两行输出均为 1,当 a 的智能指针成员指向 bb 的智能指针成员指向 a 后,两个智能指针的引用计数器又加 1,因此最后两行输出为 2,此时程序运行结束,ab 均离开作用域,则引用计数起减 1,此时两个智能指针的引用计数器为 1,认为还有指针指向内存,无法调用两个类的析构函数,造成内存泄露。

通过使用 weak_ptr 可以解决改问题,weak_ptr 是一种不控制所指向对象生存期的智能指针,它指向一个 shared_ptr 管理的对象。将一个 weak_ptr 绑定到一个 shared_ptr 也不会改变 shared_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
31
32
33
34
35
36
37
38
39
#include <iostream>  
#include <memory>
using namespace std;
class B;

class A
{
public:
weak_ptr<B> a;
~A()
{
cout << "delete class A" << endl;
}
};

class B
{
public:
weak_ptr<A> b;
~B()
{
cout << "delete class B" << endl;
}
};

int main()
{
shared_ptr<A> a = make_shared<A>();
shared_ptr<B> b = make_shared<B>();
cout << "a use count:" << a.use_count() << endl;
cout << "b use count:" << b.use_count() << endl;

a->a = b;
b->b = a;
cout << "a use count:" << a.use_count() << endl;
cout << "b use count:" << b.use_count() << endl;

return 0;
}

运行结果:

1
2
3
4
5
6
a use count:1
b use count:1
a use count:1
b use count:1
delete class B
delete class A