智能指针weak_ptr用途

来源:互联网 发布:苹果udid定制软件 编辑:程序博客网 时间:2024/05/01 08:26

由于boost库里的shared_ptr采用引用计数的技术,这个技术天生就存在一个缺陷,就是不能存在循环引用的情况,因为这个缺点,引用计数的技术一直没有用到垃圾回收的算法里。既然存在这方面的问题,作为C++强大的boost库,一定会想办法解决的。因此,就提出另外一个智能指针weak_ptr。这个智能指针只对引用的指针进行保存,但不增加引用指针的计数,因而它不对shared_ptr的指针具有拥有权,只有使用权,并且当shared_ptr的指针删除可以判断这个指针是否还有效。

 

我们先来看一个循环引用的例子,在这个例子里,由于循环引用导致shared_ptr的指针不会删除分配的内存,如下:

[cpp] view plaincopy
  1. //循环引用shared_ptr,导致内存泄漏  
  2. class CObjB;  
  3. class CObjA  
  4. {  
  5. public:  
  6.     ~CObjA()  
  7.     {  
  8.         std::cout << "~CObjA" << std::endl;  
  9.     }  
  10.   
  11.     boost::shared_ptr< CObjB > m_pB;  
  12. };  
  13.   
  14. class CObjB  
  15. {  
  16. public:  
  17.     ~CObjB()  
  18.     {  
  19.         std::cout << "~CObjB" << std::endl;  
  20.     }  
  21.   
  22.     boost::shared_ptr< CObjA > m_pA;  
  23. };  
  24.   
  25. //使用weak_ptr  
  26. //软件开发人员: 蔡军生  2013-02-09  
  27. void TestCycle(void)  
  28. {  
  29.     //  
  30.     boost::shared_ptr< CObjA > pA(new CObjA);  
  31.     boost::shared_ptr< CObjB > pB(new CObjB);  
  32.   
  33.     std::cout << "pA Count1:" << pA.use_count() << std::endl;  
  34.     std::cout << "pB Count1:" << pB.use_count() << std::endl;  
  35.     pA->m_pB = pB;  
  36.   
  37.     std::cout << "pA Count2:" << pA.use_count() << std::endl;  
  38.     std::cout << "pB Count2:" << pB.use_count() << std::endl;  
  39.   
  40.     pB->m_pA = pA;  
  41.   
  42.     std::cout << "pA Count3:" << pA.use_count() << std::endl;  
  43.     std::cout << "pB Count3:" << pB.use_count() << std::endl;  
  44. }  

在上面的例子里,当函数运行完成之后,发现并没有调用析构函数,运行的结果如下:

pA Count1:1

pB Count1:1

pA Count2:1

pB Count2:2

pA Count3:2

pB Count3:2

请按任意键继续. . .

 

由于循环引用存在,导致引用计数不再能减到0,因此不会释放内存,导致内存泄漏出现。接着再来看一下使用weak_ptr的例子,就不会出现这种情况,如下:

[cpp] view plaincopy
  1. //采用weak_ptr打破循环引用  
  2. class CObjBW;  
  3. class CObjAW  
  4. {  
  5. public:  
  6.     ~CObjAW()  
  7.     {  
  8.         std::cout << "~CObjAW" << std::endl;  
  9.     }  
  10.   
  11.     boost::shared_ptr< CObjBW > m_pB;  
  12. };  
  13.   
  14. class CObjBW  
  15. {  
  16. public:  
  17.     ~CObjBW()  
  18.     {  
  19.         std::cout << "~CObjBW" << std::endl;  
  20.     }  
  21.   
  22.     boost::weak_ptr< CObjAW > m_pA;  
  23. };  
  24.   
  25. void TestWeakPtr(void)  
  26. {  
  27.     //  
  28.     boost::shared_ptr< CObjAW > pA(new CObjAW);  
  29.     boost::shared_ptr< CObjBW > pB(new CObjBW);  
  30.   
  31.     std::cout << "pA Count1:" << pA.use_count() << std::endl;  
  32.     std::cout << "pB Count1:" << pB.use_count() << std::endl;  
  33.     pA->m_pB = pB;  
  34.   
  35.     std::cout << "pA Count2:" << pA.use_count() << std::endl;  
  36.     std::cout << "pB Count2:" << pB.use_count() << std::endl;  
  37.   
  38.     pB->m_pA = pA;  
  39.   
  40.     std::cout << "pA Count3:" << pA.use_count() << std::endl;  
  41.     std::cout << "pB Count3:" << pB.use_count() << std::endl;  
  42. }  

在这个例子里,跟前面的例子唯一的区别就是使用boost::weak_ptr,运行的结果如下:

pA Count1:1

pB Count1:1

pA Count2:1

pB Count2:2

pA Count3:2

pB Count3:2

请按任意键继续. . .

pA Count1:1

pB Count1:1

pA Count2:1

pB Count2:2

pA Count3:1

pB Count3:2

~CObjAW

~CObjBW

请按任意键继续. . .

 

从结果可以看到这个例子的对象会调用析构函数,因此对象也被正确地析构,表明对象的内存也回收了。

当我们发现程序有递归,或者循环引用的情况下,就需要小心智能指针shared_ptr的使用,合理地使用智能指针weak_ptr就可以避免出错。

智能指针weak_ptr还另外两个用处,当你只需要使用一下对象,但不想拥有对象生命周期,当对象删除时又得到通知。最后一个用处就是可以得到对象的指针是否有效的判断。

0 0