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以后再进行访问。

 

相关链接

C++类型转换 https://www.cnblogs.com/yongjin-hou/p/14391180.html

posted @ 2021-02-10 13:06  封狼居胥!  阅读(97)  评论(0编辑  收藏  举报