C++智能指针
C++有4个智能指针,auto_ptr,shared_ptr,weak_ptr,unique_ptr,其中auto_ptr只有C++98支持,C++11已经弃用。
为什么要使用智能指针?
当申请的空间在函数结束时未进行释放时,会造成内存泄漏;
使用智能指针可以避免内存泄漏;智能指针是一个类,用于管理一个指针,当超出了类的作用域时,会自动调用析构函数,自动释放内存空间。
auto_ptr:
auto_ptr采用所有权模式。
1 auto_ptr<string> p1(new string ("hello") ;
2 auto_ptr<string> p2;
3
4 //p2剥夺了p1的所有权
5 //当后续访问p1时将会出错
6 p2 = p1;
unique_ptr:
unique_ptr能够实现独占式拥有,保证只有一个智能指针指向该对象;能够避免内存泄漏;用于替换auto_ptr。
1 unique_ptr<string> p1 (new string ("hello");
2 unique_ptr<string> p2;
3
4 //出错,p1独占拥有new的对象
5 //避免了auto_ptr中,p1不再指向有效数据的问题
6 p2= p1;
当程序将一个unique_ptr对象赋值给另一个unique_ptr对象时,如果源unique_ptr对象已经存在,则不能编译通过;如果源unique_ptr对象是一个临时右值,可以编译通过;
1 unique_ptr<string> p1(new string ("hello"));
2 unique_ptr<string> p2;
3
4 //不可以编译通过
5 //将一个已经存在的p1赋值给p2,会留下悬挂的p1
6 p2 = p1;
7
8 unique_ptr<string> p3;
9 //可以编译通过
10 //将一个临时右值赋值给p3,不会留下悬挂的指针
11 p3 = unique_ptr<string>(new string ("world"));
将临时右值赋值给p3时,调用unique_ptr的构造函数创建一个临时对象unique_ptr<string>(new string ("world")),其所有权让给p3之后,会自动销毁,所以不会留下悬挂的指针。
shared_ptr:
shared_ptr能够实现共享式拥有,多个智能指针可以指向相同的对象,该资源会在最后一个引用被销毁的时候(计数等于0时)释放,使用计数机制来表示对象被几个智能指针所共享;shared_ptr对象可以通过new来构造,也可以通过传入unique_ptr和weak_ptr来构造。
shared_ptr的成员函数:
use_count()-返回引用计数的个数;
unique()-返回是否独占式拥有;
swap()-交换两个智能指针所指向的对象;
release()-当前指针释放资源所有权,计数减1;
1 string *s1 = new string("hello");
2 shared_ptr<string> ps1(s1);
3 shared_ptr<string> ps2;
4 ps2 = ps1;
5
6 //use_count(),返回引用计数的个数
7 //输出2,共有两个智能指针ps1和ps2指向字符串"hello"
8 cout << ps1.use_count()<<endl;
9 cout << ps2.use_count()<<endl;
10
11 //unique(),返回ps1是否独占式拥有对象
12 //输出0,ps1和ps2共享对象
13 cout << ps1.unique()<<endl;
14
15 string *s3 = new string("world");
16 shared_ptr<string> ps3(s3);
17 //交换ps1和ps3所拥有的对象
18 swap(ps1, ps3);
19
20 //输出1,只有一个智能指针ps1指向字符串"world"
21 cout << ps1.use_count()<<endl;
22 //输出2,共有两个智能指针ps2和ps3指向字符串"hello"
23 cout << ps2.use_count() << endl;
24
25 //当前指针ps2释放资源所有权,计数减一
26 ps2.release();
27 //输出1,只有一个智能指针ps3指向字符串"hello"
28 cout << ps2.use_count() << endl;
weak_ptr:
weak_ptr是一种不控制对象生命周期的智能指针,指向一个shared_ptr管理的对象;weak_ptr是一种弱引用,不会增加对象的引用计数,只提供对该对象的访问手段;而shared_ptr是一种强引用,会增加对象的引用计数,对该对象进行内存管理;
weak_ptr用来解决shared_ptr相互引用时的死锁问题。
1 class B; //声明
2
3 class A
4 {
5 public:
6 shared_ptr<B> pb_;
7 };
8
9 class B
10 {
11 public:
12 shared_ptr<A> pa_;
13 };
14
15 void fun()
16 {
17 //智能指针pa指向类A的对象,智能指针pb指向类B的对象
18 //此时,pa和pb的引用计数均为1
19 //pa指向了类A的对象,pb指向了类B的对象
20 shared_ptr<A> pa(new A());
21 shared_ptr<B> pb(new B());
22
23 //初始化类内的shared_ptr成员
24 //pa_也指向了类A的对象,pb_也指向了类B的对象
25 pb->pa_ = pa;
26 pa->pb_ = pb;
27
28 //此时,pa和pb的引用计数均为2
29 cout << pa.use_count() << endl;
30 cout << pb.use_count() << endl;
31 }
32
33 int main()
34 {
35 fun();
36 return 0;
37 }
pa和pb之间相互引用,两个资源的引用计数均为2;当跳出fun函数时,智能指针pa和pb析构,两个资源的引用计数均变为1,两个资源没有被释放(类A和类B的析构函数没有被调用),造成死锁。
当把类A中的shared_ptr改为weak_ptr后,资源A的引用计数为2,资源B的引用计数为1;当跳出fun函数时,智能指针pa和pb析构,资源A的引用计数变为1,资源B的引用计数变为0,资源B释放;资源B释放以后,是的资源A的引用计数变为0,资源A得到释放。
void fun()
{
//智能指针pa指向类A的对象,智能指针pb指向类B的对象
//此时,pa和pb的引用计数均为1
//pa指向了类A的对象,pb指向了类B的对象
shared_ptr<A> pa(new A());
shared_ptr<B> pb(new B());
//初始化类内的shared_ptr成员
//pa_也指向了类A的对象,pb_也指向了类B的对象
pb->pa_ = pa;
pa->pb_ = pb;
//此时,pa的引用计数均为2,pb的引用计数为1
cout << pa.use_count() << endl;
cout << pb.use_count() << endl;
}
shared_ptr和weak_ptr之间可以相互转换,shared_ptr可以直接赋值给weak_ptr,weak_ptr通过调用lock函数转换为shared_ptr从而赋值给shared_ptr;此外,不能通过weak_ptr直接访问对象的方法,应该先把其转换为shared_ptr以后再进行访问。
相关链接