shared_ptr造成的循环引用&&解决方法和原理(弱引用&&强引用)

来源:互联网 发布:人工智能的最新发展 编辑:程序博客网 时间:2024/05/19 04:02

《***》循环引用就是由于智能指针shared_ptr造成的,下面就是shared_ptr的使用造成循环引用的图解:

《****》举个例子来说下shared_ptr造成的循环引用:

(选题背景双向链表)

[cpp] view plain copy
  1. <span style="font-size:18px;">#include<memory>  
  2. #include<iostream>  
  3. using namespace std;  
  4.   
  5. struct Node  
  6. {  
  7.     shared_ptr<Node> _pre;  
  8.     shared_ptr<Node> _next;  
  9.   
  10.     ~Node()  
  11.     {  
  12.         cout << "~Node():" << this << endl;  
  13.     }  
  14.     int data;  
  15. };  
  16.   
  17. void FunTest()  
  18. {  
  19.     shared_ptr<Node> Node1(new Node);  
  20.     shared_ptr<Node> Node2(new Node);  
  21.     Node1->_next = Node2;  
  22.     Node2->_pre = Node1;  
  23.   
  24.     cout << "Node1.use_count:"<<Node1.use_count() << endl;  
  25.     cout << "Node2.use_count:"<< Node2.use_count() << endl;  
  26. }  
  27.   
  28. int main()  
  29. {  
  30.     FunTest();  
  31.     system("pause");  
  32.     return 0;  
  33. }</span>  


执行结果:

(说明:shared_ptr的使用使得一块空间有两个对象管理,即头个结点的_next域和下一个指针共同管理,或者又头一个指针和第二个结点的_ptr域共同管理所以其_pCount=2)

针对上面出现的由于引用计数和管理空间的对象的个数导致空间不能释放的结果就是循环引用。

针对循环引用我们有三种解决方案:

      《1》当只剩下最后一个引用的时候需要手动打破循环引用释放对象。

2       《2》parent的生存期超过children的生存期的时候,children改为使用一个普通指针指向parent

3       《3》使用弱引用的智能指针打破这种循环引用。虽然这三种方法都可行,但方法1和方法2都需要程序员手动控制

    容易出错切不易操作。

  *什么是强引用和弱引用 

   一个强引用是指当被引用的对象仍活着的话,这个引用也存在(也就是说,只要至少有一个强引用,那么这个对象 就不会也不能被释放)。

    boost::share_ptr就是强引用。

    相对而言,弱引用当引用的对象活着的时候不一定存在。仅仅是当它自身存在的时的一个引用。

    弱引用并不修改该对象的引用计数,这意味这弱引用它并不对对象的内存进行管理。

    在功能上类似于普通指针,然而一个比较大的区别是,弱引用能检测到所管理的对象是否已经被释放,从而避免访问非法内存 r

    weak_ptr的出现就是为了辅助shared_ptr的工作,弥补shared_ptr的不足,解决shared_ptr造成的循环引用问题,而weak_ptr的这种解决方法也就是弱引用。

 

[cpp] view plain copy
  1. #include<memory>  
  2. #include<iostream>  
  3. using namespace std;  
  4.   
  5. struct Node  
  6. {  
  7.     weak_ptr<Node> _pre;  
  8.     weak_ptr<Node> _next;  
  9.   
  10.     ~Node()  
  11.     {  
  12.         cout << "~Node():" << this << endl;  
  13.     }  
  14.     int data;  
  15. };  
  16.   
  17. void FunTest()  
  18. {  
  19.     shared_ptr<Node> Node1(new Node);  
  20.     shared_ptr<Node> Node2(new Node);  
  21.     Node1->_next = Node2;  
  22.     Node2->_pre = Node1;  
  23.   
  24.     cout <<"Node1.use_count:"<< Node1.use_count() << endl;  
  25.     cout <<"Node2.use_count:"<< Node2.use_count() << endl;  
  26. }  
  27.   
  28. int main()  
  29. {  
  30.     FunTest();  
  31.     system("pause");  
  32.     return 0;  
  33. }<  


 

  执行结果:

 

   *从上面的结果看,很明显,在用了智能指针weak_ptr后调用了析构函数,释放了空间,而shead_ptr则没有释放空间.

《*》在讲循环引用之前首先必须了解下什么是智能指针:

     

《**》下面就有关循环引用的两个指针shared_ptr和weak_ptr逐一分析下:

shared_ptr:

       

shared_ptr完成了你所希望的工作:他负责在不使用实例时删除由它指向的对象(pointee),并且它可以自由的共享它指向的对象(pointee)

weak_ptr:

        weak_ptr是为配合shared_ptr而引入的一种智能指针来协助shared_ptr工作,它可以从一个shared_ptr或另一个weak_ptr对象构造,它的构造和析构不会引起引用记数的增加或减少。没有重载*->但可以使用lock获得一个可用的shared_ptr对象。

weak_ptr的一个重要用途是通过lock获得this指针的shared_ptr,使对象自己能够生产shared_ptr来管理自己,但助手类enable_shared_from_thisshared_from_this会返回thisshared_ptr,只需要让想被shared_ptr管理的类从它继承即可