分享

智能指针

 黄建校 2015-11-21

智能指针就是存储指向堆上分配的对象的指针,行为上与C++的原生指针基本一致,区别是不需要管理对象的销毁。智能指针可以选择在适当的时机销毁对象,可以大幅降低空悬指针和野指针等错误。所有智能指针如果是非类成员,一般都是栈上分配的对象。这里介绍boost库的智能指针,主要有:

1. scoped_ptr

概念上讲,智能指针意味着持有它所指向对象的拥有权,有责任在该对象不在需要时对其销毁。scoped_ptr只提供了RAII机制,对它指向的对象具有唯一的拥有权,不会被共享和转移。这是通过不可拷贝实现的,所以scoped无法存放到stl容器中指向的对象在scoped_ptr析构或者reset后会被释放。scoped_ptr实现很简单,基本与原生指针性能差不多。scoped_ptr用在类成员时,可以避免在析构函数中释放指针。

  1. class A {  
  2. ...  
  3. private:  
  4.     B *obj;  
  5. };  
类A的析构函数不得不对指针obj进行delete操作,而改成scoped_ptr则可以避免:
  1. class A {  
  2. ...  
  3. private:  
  4.     boost::scoped_ptr<B> obj;  
  5. };  

2. shared_ptr

以引用计数的方式共享指针的拥有权。当最后一个shared_ptr被销毁时,指向的对象也会被销毁。由于使用引用计数,无法解决循环引用的问题。shared_ptr实现了拷贝构造函数和赋值运算符,可以存放到stl容器中。同时,也实现了比较运算符,可以存放到关联容器中。

如果T *可以隐式转化(通过static_cast)为U *,那么shared_ptr<T>也可以隐式转化为shared_ptr<U>。

线程安全反面,shared_ptr支持:a. 并发读,b. 并发写多个不同的实例,c. 不支持并发读写同一个实例(需加锁)。

下列程序存在循环引用:

  1. #include <iostream>                                                                                                                               
  2.   
  3. #include <boost/shared_ptr.hpp>                                                                                                                   
  4. #include <boost/weak_ptr.hpp>                                                                                                                     
  5.   
  6. using namespace std;                                                                                                                              
  7. using namespace boost;                                                                                                                            
  8.       
  9. class B;                                                                                                                                          
  10.      
  11. class A {                                                                                                                                         
  12. public:                                                                                                                                           
  13.     ~A() {                                                                                                                                        
  14.         cout << "ref count of B: " << bptr.use_count() << endl;                                                                                   
  15.         cout << "deconstruct A" << endl;                                                                                                          
  16.     }                                                                                                                                             
  17.       
  18.     shared_ptr<B> bptr;                                                                                                                           
  19. };                                                                                                                                                
  20.   
  21. class B {                                                                                                                                         
  22. public:                                                                                                                                           
  23.     ~B() {                                                                                                                                        
  24.         cout << "ref count of A: " << aptr.use_count() << endl;                                                                                   
  25.         cout << "deconstruct B" << endl;                                                                                                          
  26.     }                                                                                                                                             
  27.   
  28.     shared_ptr<A> aptr;                                                                                                                         
  29. };                                                                                                                                                
  30.   
  31. void test()                                                                                                                                       
  32. {                                                                                                                                                 
  33.     cout << "begin" << endl;                                                                                                                      
  34.     shared_ptr<A> aptr(new A);                                                                                                                    
  35.     shared_ptr<B> bptr(new B);      
  36.       
  37.     aptr->bptr = bptr;     
  38.     bptr->aptr = aptr;                                                                                                                           
  39.   
  40.     cout << "ref count of bptr: " << bptr.use_count() << endl;                                                                                    
  41.     cout << "ref count of aptr: " << aptr.use_count() << endl;                                                                                   
  42.   
  43.     cout << "end" << endl;                                                                                                                        
  44. }                                                                                                                                                 
  45.   
  46. int main()                                                                                                                                        
  47. {                                                                                                                                                 
  48.     test();                                                                                                                                       
  49.     cout << "after test" << endl;                                                                                                                 
  50. }     

运行程序,可以发现A和B都没有被析构。下面通过weak_ptr解决这种循环引用的问题。

  1. begin  
  2. ref count of bptr: 2  
  3. ref count of aptr: 2  
  4. end  
  5. after test  

3. weak_ptr

weak_ptr不管理对象的生命周期,但是可以感知一个对象的生死。weak_ptr是弱引用,用它指向一个对象,不会增加其引用计数。weak_ptr指向的对象底层有shared_ptr管理,要通过weak_ptr访问这个对象,必须构造成shread_ptr才行。具体可以通过shared_ptr的构造函数或者是lock方法。当最后一个指向该对象的shared_ptr被销毁时,该对象也会被销毁。此时,调用shared_ptr的构造函数会抛出boost::bad_weak_ptr异常,lock返回的shared_ptr是空的。

weak_ptr实现了拷贝构造函数、赋值运算符和比较运算符所以可以放入stl容器和关联容器中。

下面看一下,weak_ptr是如何解决循环引用,将类B中指向aptr的shared_ptr改为weak_ptr即可。

  1. #include <iostream>                                                                                                                               
  2.                                                                                                                                                   
  3. #include <boost/shared_ptr.hpp>                                                                                                                   
  4. #include <boost/weak_ptr.hpp>                                                                                                                     
  5.                                                                                                                                                   
  6.                                                                                                                                                   
  7. using namespace std;                                                                                                                              
  8. using namespace boost;                                                                                                                            
  9.                                                                                                                                                   
  10. class B;                                                                                                                                          
  11.                                                                                                                                                   
  12. class A {                                                                                                                                         
  13. public:                                                                                                                                           
  14.     ~A() {                                                                                                                                        
  15.         cout << "ref count of B: " << bptr.use_count() << endl;                                                                                   
  16.         cout << "deconstruct A" << endl;                                                                                                          
  17.     }                                                                                                                                             
  18.                                                                                                                                                   
  19.     shared_ptr<B> bptr;                                                                                                                           
  20. };                                                                                                                                                
  21.                                                                                                                                                   
  22. class B {                                                                                                                                         
  23. public:                                                                                                                                           
  24.     ~B() {                                                                                                                                        
  25.         cout << "ref count of A: " << aptr.use_count() << endl;                                                                                   
  26.         cout << "deconstruct B" << endl;                                                                                                          
  27.     }                                                                                                                                                                                                                                                              
  28.     weak_ptr<A> aptr;                                                                                                                             
  29. };                                                                                                                                                
  30.                                                                                                                                                   
  31. void test()                                                                                                                                       
  32. {                                                                                                                                                 
  33.     cout << "begin" << endl;                                                                                                                      
  34.     shared_ptr<A> aptr(new A);                                                                                                                    
  35.     shared_ptr<B> bptr(new B);                                                                                                                    
  36.                                                                                                                                                   
  37.     weak_ptr<A> waptr(aptr);                                                                                                                      
  38.                                                                                                                                                   
  39.     aptr->bptr = bptr;                                                                                                                            
  40.     bptr->aptr = waptr;                                                                                                                           
  41.                                                                                                                                                   
  42.     cout << "ref count of bptr: " << bptr.use_count() << endl;                                                                                    
  43.     cout << "ref count of aptr: " << waptr.use_count() << endl;                                                                                   
  44.                                                                                                                                                   
  45.     cout << "end" << endl;                                                                                                                        
  46. }                                                                                                                                                 
  47.                                                                                                                                                   
  48. int main()                                                                                                                                        
  49. {                                                                                                                                                 
  50.     test();                                                                                                                                       
  51.     cout << "after test" << endl;                                                                                                                 
  52. }     
运行结果:

  1. begin  
  2. ref count of bptr: 2  
  3. ref count of aptr: 1  
  4. end  
  5. ref count of B: 1  
  6. deconstruct A  
  7. ref count of A: 0  
  8. deconstruct B  
  9. after test  
可以看到A和B都被析构了,并且在test函数的结尾处,检查aptr的引用计数是1,而bptr是2,这是因为weak_ptr指向这个对象,不会引起引用计数的改变。





    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多