c++智能指针

来源:互联网 发布:人工智能与智慧物流 编辑:程序博客网 时间:2024/06/18 16:34

在c++中,动态内存管理是通过运算符new来开辟空间的,然后用delete来释放这个空间。

       动态内存很容易出现问题,因为确保在正确的时间释放内存是很困难的。有时我们会忘记释放内存,这样就会造成内存泄露;有时在还有指针引用内存的时候就释放了它,这时就会出现引用非法内存的指针。

举个例子:

[cpp] view plain copy
  1. void Test ()  
  2. {  
  3. int* p1 = new int(1);  
  4. bool isEnd = true;  
  5. //...  
  6. if (isEnd )  
  7. {  
  8. delete p1 ;  
  9. return;  
  10. }  
  11. //...  
  12. delete p1;  
  13. }  
如果在1f判断中我们忘记delete  p1  ,直接return,那么这块内存就没有释放,很容易造成内存泄露。

所以我们需要使用智能指针来管理动态对象。

所谓智能指针就是智能/自动化的管理指针所指向的动态资源的释放。

STL--auto_ptr

Boost库的智能指针(ps:新的C++11标准中已经引入了
unique_ptr/shared_ptr/weak_ptr

下面我们分别来看一下这几个智能指针:

1)scoped_ptr:


这是比较简单的一种智能指针,正如其名字所述,scoped_ptr所指向的对象在作用域之外会自动得到析构,scoped_ptr是non-copyable的,也就是说你不能去尝试复制一个scoped_ptr的内容到另外一个scoped_ptr中,这也是为了防止错误的多次析构同一个指针所指向的对象。顾名思义,守卫的指针,思想就是防拷贝,在大多时候用不到拷贝构造和赋值运算符重载,那么我们做的就是写出构造函数和析构函数,拷贝构造和赋值运算符重载只声明不定义。

[cpp] view plain copy
  1. template<class T>  
  2. class ScopedPtr  
  3. {  
  4. public:  
  5.     ScopedPtr(T* ptr)  
  6.         :_ptr(ptr)  
  7.     {}  
  8.    
  9.      ScopedPtr()  
  10.         :_ptr(NULL)  
  11.     {}  
  12.    
  13.     ~ScopedPtr()  
  14.     {  
  15.         if (_ptr)  
  16.         {  
  17.             delete _ptr;  
  18.             _ptr = NULL;  
  19.         }  
  20.     }  
  21.    
  22.     T& operator*()  
  23.     {  
  24.         return *_ptr;  
  25.     }  
  26.    
  27.     T* GetPtr()  
  28.     {  
  29.         return _ptr;  
  30.     }  
  31.    
  32. protected:  
  33.     ScopedPtr<T>(const ScopedPtr<T>& p);  
  34.     ScopedPtr<T>& operator = (const ScopedPtr<T>& p);  
  35.    
  36. private:  
  37.     T* _ptr;  
  38. };  
  39.    
  40. void Test()  
  41. {  
  42.     ScopedPtr<int> p1(new int(2));  
  43.     ScopedPtr<int> p2=p1;  
  44.     ScopedPtr<int> p3(new int(3));  
  45.     p3 = p1;  
  46. }  
  47.    
  48. int main()  
  49. {  
  50.     Test();  
  51.     system("pause");  
  52.     return 0;  
  53. }  
2)shared_ptr:

shared_ptr是一个最像指针的"智能指针".
 shared_ptr与scoped_ptr一样包装了new操作符在堆上分配的动态对象,但它实现的是引用计数型的智能指针,可以被自由的拷贝和赋值,在任意的地方共享它,当没有代码使用(引用计数为0)它时才能删除被包装的动态分配的对象。shared_ptr也可以安全地放到标准容器中,并弥补了auto_ptr因为转移语义而不能把指针做为STL容器元素的缺陷。

下面我们来实现以下这个智能指针。

[cpp] view plain copy
  1. #pragma once  
  2. template<class T>  
  3. class Sharedptr  
  4. {  
  5. public:  
  6.     Sharedptr()  
  7.         :_ptr(NULL)  
  8.         , _pcount(new int(1))  
  9.     {}  
  10.     Sharedptr(T *ptr)  
  11.         :_ptr(ptr)  
  12.         , _pcount(new int(1))  
  13.     {}  
  14.     Sharedptr(const Sharedptr<T>& sp)  
  15.         :_ptr(sp._ptr)  
  16.         , _pcount(sp._pcount)  
  17.     {  
  18.         ++(*_pcount);  
  19.     }  
  20.     ~Sharedptr()  
  21.     {  
  22.         if (_ptr)  
  23.         {  
  24.             if (--(*_pcount)==0)  
  25.             {  
  26.                 delete _ptr;  
  27.                 delete _pcount;  
  28.                 _ptr = NULL;  
  29.                 _pcount = NULL;  
  30.             }  
  31.             _ptr = NULL;  
  32.         }  
  33.     }  
  34.     Sharedptr<T>& operator=(const Sharedptr<T> &sp)  
  35.     {  
  36.         if (this != &sp)  
  37.         {  
  38.             if (--(*_pcount) == 0)  
  39.             {  
  40.                 delete _ptr;  
  41.                 delete _pcount;  
  42.                 _ptr = NULL;  
  43.                 _pcount = NULL;  
  44.             }  
  45.             _ptr = sp._ptr;  
  46.             _pcount = sp._pcount;  
  47.             ++(*_pcount);  
  48.         }  
  49.         return *this;  
  50.     }  
  51. private:  
  52.     T* _ptr;  
  53.     int *_pcount;  
  54. };  
  55. void test()  
  56. {  
  57.     int *a = new int(5);  
  58.     Sharedptr<int> ap1(a);  
  59.     Sharedptr<int> ap2(ap1);  
  60.     Sharedptr<int> ap3;  
  61.     ap3 = ap2;  
  62. }  
  63. int main()  
  64. {  
  65.     test();  
  66.     system("pause");  
  67.     return 0;  
  68. }  

2)auto_ptr:

auto_ptr 是C++标准库提供的类模板,auto_ptr对象通过初始化指向由new创建的动态内存,它是这块内存的拥有者,一块内存不能同时被分给两个拥有者。当auto_ptr对象生命周期结束时,其析构函数会将auto_ptr对象拥有的动态内存自动释放。即使发生异常,通过异常的栈展开过程也能将动态内存释放。auto_ptr不支持new 数组。

但是它有缺陷,STL容器在分配内存的时候,必须要能够拷贝构造容器的元素。而且拷贝构造的时候,不能修改原来元素的值。而auto_ptr在拷贝构造的时候,一定会修改元素的值。所以STL元素不能使用auto_ptr。

所以最好不要使用。

下面是代码实现:

[cpp] view plain copy
  1. template<class T>  
  2. class Autoptr  
  3. {  
  4. public:  
  5.       
  6.     Autoptr(T *ptr)  
  7.         :_ptr(ptr)  
  8.     {}  
  9.     Autoptr()  
  10.         :_ptr(NULL)  
  11.     {}  
  12.     Autoptr<T>(Autoptr<T>& a)  
  13.         :_ptr(a._ptr)  
  14.     {  
  15.         a._ptr = NULL;  
  16.     }  
  17.     ~Autoptr()  
  18.     {  
  19.         if (_ptr)  
  20.         {  
  21.             delete _ptr;  
  22.             _ptr = NULL;  
  23.         }  
  24.     }  
  25.     Autoptr<T>& operator=(Autoptr<T>&a)  
  26.     {  
  27.         if (this != &a)  
  28.         {  
  29.             delete _ptr;  
  30.             _ptr = a._ptr;  
  31.             a._ptr = NULL;  
  32.         }  
  33.         return *this;  
  34.     }  
  35.     T& operator*()  
  36.     {  
  37.         return *_ptr;  
  38.     }  
  39.     T* Getptr()  
  40.     {  
  41.         return _ptr;  
  42.     }  
  43.    
  44. protected:  
  45.     T *_ptr;  
  46. };  
  47. void test()  
  48. {  
  49.     Autoptr<int> ap0(new int(5));  
  50. <span style="white-space:pre">    </span>Autoptr<int> ap1(ap0);  
  51. <span style="white-space:pre">    </span>cout << *ap1 << endl;  
  52.     Autoptr<int> ap2(ap1);  
  53.     cout << *ap2 << endl;  
  54.     Autoptr<int> ap3;  
  55.     ap3 = ap2;  
  56.     cout << *ap3 << endl;  
  57. }  
  58.   
  59. int main()  
  60. {  
  61.     test();  
  62.     return 0;  
  63. }  

希望对大家有所帮助。

最后总结一下:

1、在可以使用 boost 库时,不要使用 std::auto_ptr,因为其不仅不符合 C++ 编程思想,而且极容易出错。

2、在确定对象无需共享的情况下,使用 boost::scoped_ptr(动态数组使用boost::scoped_array)。

3、在对象需要共享的情况下,使用 boost::shared_ptr(动态数组使用boost::shared_array)。

4、在需要访问 boost::shared_ptr 对象,而又不想改变其引用计数的情况下,使用boost::weak_ptr。

原创粉丝点击