关闭

智能指针

82人阅读 评论(0) 收藏 举报
分类:

RAII(Resource Acquisition Is Initialization):


资源分配即初始化,定义封装一个类,用来实现调用构造函数时就可完成资源的分配和初始化,在调用析构函数就可完成资源的清理,以实现对资源的初始化和清理。


智能指针:


用自动化或者说智能的指针来实现对动态内存的释放。

它是一个类,有类似指针的功能。


常见的智能指针有:auto_ptr/scoped_ptr/scoped_array/shared_ptr/shared_array


一、AutoPtr

首先,先介绍AutoPtr,为防止一块空间释放两次浅拷贝导致的崩溃情况,我们的思想是权限转移,就是说你拷贝时要将你的两个指针指向同一块空间,可是这样会程序崩溃。解决如下:


1)老版AutoPtr

主要变量是_ptr,_owner,用bool型的_owner来控制权限转移,当它为false值时释放空间,保证释放一次。

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


缺陷:

[cpp] view plain copy
  1. if(……)  
  2. {  
  3.      AutoPtr<int> ap2(ap1);  
  4.      ……  
  5. }  

出了作用域后ap2会释放空间还给系统,而ap2仍指向这块空间,会出现野指针。

wKioL1b3owbibxRCAAATFI5Rwkc178.png

2)新版AutoPtr

我们及时将之前的指针置成空,将这块空间的所有权交给现在的指针。



[cpp] view plain copy
  1. #include<iostream>  
  2. using namespace std;  
  3.   
  4. template<class T>  
  5. class AutoPtr  
  6. {  
  7. public:  
  8.     AutoPtr(T* ptr)  
  9.     :_ptr(ptr)  
  10.     {}  
  11.   
  12.     AutoPtr()  
  13.     :_ptr(NULL)  
  14.     {}  
  15.   
  16.     AutoPtr<T>(AutoPtr<T>& ap)    //权限转移  
  17.         : _ptr(ap._ptr)  
  18.     {  
  19.         ap._ptr = NULL;  
  20.     }  
  21.   
  22.     AutoPtr<T>& operator=(AutoPtr<T>& ap)  
  23.     {  
  24.         if (&ap != this)  
  25.         {  
  26.             delete _ptr;  
  27.             _ptr = ap._ptr;  
  28.             ap._ptr = NULL;     //权限转移  
  29.         }  
  30.         return *this;  
  31.     }  
  32.   
  33.     ~AutoPtr()  
  34.     {  
  35.         if (_ptr)  
  36.         {  
  37.             delete _ptr;  
  38.             _ptr = NULL;  
  39.         }  
  40.     }  
  41.   
  42.     T& operator*()  
  43.     {  
  44.         return *_ptr;  
  45.     }  
  46.   
  47. private:  
  48.     T* _ptr;  
  49. };  
  50.   
  51. void Test()  
  52. {  
  53.     AutoPtr<int> ap1(new int(2));  
  54.     AutoPtr<int> ap2 = ap1;  
  55.     AutoPtr<int> ap3(new int(3));  
  56.     ap3 = ap1;  
  57. }  
  58.   
  59. int main()  
  60. {  
  61.     Test();  
  62.     system("pause");  
  63.     return 0;  
  64. }  


二、ScopedPtr


这是最实用的智能指针。


顾名思义,守卫的指针,思想就是防拷贝,在大多时候用不到拷贝构造和赋值运算符重载,那么我们做的就是写出构造函数和析构函数,拷贝构造和赋值运算符重载只声明不定义。这里有几点要说明:


(1)鉴于上面,我们写智能指针时,将拷贝构造和赋值运算符重载设置成保护或者私有的,这样就可以保证其他人在不知情的情况下(以为是我们忘记写定义了)无法写拷贝构造和赋值运算符重载的定义。


(2)既然不要定义,那为什么要声明呢,是不是可以不要,或许你们会这样想。不可以!原因是你不写,编译器会自动调用系统自身的拷贝构造和赋值运算符重载,这样就没办法做到防拷贝了。


下面,我们用ScopedPtr来实现简易版本的智能指针。


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


三、SharedPtr


共享指针,即思想就是引用计数,引入变量指针变量pCount,指向一块空间,对其计数,当只有一个指针指向空间时再释放资源,实现对其管理。初衷也是解决多个指针指向同一块空间释放多次会崩溃。这里不用static的整型的pCount在于,若有多个指针指向第一块空间,多个指针指向第二块空间,……,当改变一块空间的指向,该块空间的引用计数发生变化了,static的pCount会导致其他空间的引用计数也发生变化。

[cpp] view plain copy
  1. #include<iostream>  
  2. using namespace std;  
  3.   
  4. template<class T>  
  5. class SharedPtr  
  6. {  
  7. public:  
  8.     SharedPtr(T* ptr)  
  9.         :_ptr(ptr)  
  10.         , _pCount(new long(1))  
  11.     {}  
  12.   
  13.     SharedPtr()  
  14.         :_ptr(NULL)  
  15.         , _pCount(new long(1))  
  16.     {}  
  17.   
  18.     SharedPtr<T>(const SharedPtr<T>& sp)  
  19.         : _ptr(sp._ptr)  
  20.         , _pCount(sp._pCount)  
  21.     {  
  22.         ++(*_pCount);  
  23.     }  
  24.   
  25.     SharedPtr<T>& operator=(const SharedPtr<T>& sp)  
  26.     {  
  27.         if (&sp != this)  
  28.         {  
  29.             if (--(*_pCount) == 0)  
  30.             {  
  31.                 delete _ptr;  
  32.                 delete _pCount;  
  33.             }  
  34.             _ptr = sp._ptr;  
  35.             _pCount = sp._pCount;  
  36.             ++(*_pCount);  
  37.         }  
  38.         return *this;  
  39.     }  
  40.   
  41.     ~SharedPtr()  
  42.     {  
  43.         if (_ptr)  
  44.         {  
  45.             if (--(*_pCount) == 0)  
  46.             {  
  47.                 delete _ptr;  
  48.                 delete _pCount;  
  49.             }  
  50.         }  
  51.     }  
  52.   
  53.     T& operator*()  
  54.     {  
  55.         return *_ptr;  
  56.     }  
  57.   
  58.     long GetCount()  
  59.     {  
  60.         return *(_pCount);  
  61.     }  
  62.   
  63.     T* GetPtr()  
  64.     {  
  65.         return _ptr;  
  66.     }  
  67.   
  68. private:  
  69.     T* _ptr;  
  70.     long* _pCount;  
  71. };  
  72.   
  73.   
  74. void Test()  
  75. {  
  76.     SharedPtr<int> sp1 = new int(1);  
  77.     SharedPtr<int> sp2 = sp1;  
  78.     SharedPtr<int> sp3 = new int(2);  
  79.     sp3 = sp1;  
  80. }  
  81.   
  82.   
  83. int main()  
  84. {  
  85.     Test();  
  86.     system("pause");  
  87.     return 0;  
  88. }  


四、ScopedArray

ScopedArray与ScopedPtr区别在于:

ScopedArray管理数组,不可实现访问单个元素,而ScopedArray数组,可实现对数组元素的操控。

[cpp] view plain copy
  1. #include<iostream>  
  2. using namespace std;  
  3. #include<assert.h>  
  4.   
  5.   
  6. template<class T>  
  7. class ScopedArray  
  8. {  
  9. public:  
  10.     ScopedArray(T* ptr = NULL)  
  11.         :_ptr(ptr)  
  12.     {}  
  13.   
  14.     ~ScopedArray()  
  15.     {  
  16.         if (_ptr)  
  17.         {  
  18.             delete [] _ptr;  
  19.             _ptr = NULL;  
  20.         }  
  21.     }  
  22.   
  23.     T& operator[](size_t index)  
  24.     {  
  25.         assert(index > 0);  
  26.         return _ptr[index];  
  27.     }  
  28.       
  29. protected:  
  30.     ScopedArray<T>(const ScopedArray<T>& sp);  
  31.     ScopedArray<T>& operator=(const ScopedArray<T>& sp);  
  32.   
  33. private:  
  34.     T* _ptr;  
  35. };  
  36.   
  37. void Test()  
  38. {  
  39.     ScopedArray<int> sp1(new int[10]);  
  40. }  
  41.   
  42. int main()  
  43. {  
  44.     Test();  
  45. }  


五、SharedPtr

同四。

[cpp] view plain copy
  1. #include<iostream>  
  2. using namespace std;  
  3. #include<assert.h>  
  4.   
  5. template<class T>  
  6. class SharedArray  
  7. {  
  8. public:  
  9.     SharedArray(T* ptr = NULL)  
  10.         :_ptr(ptr)  
  11.         , _pCount(new long(1))  
  12.     {}  
  13.   
  14.     SharedArray<T>(const SharedArray<T>& sp)  
  15.         : _ptr(sp._ptr)  
  16.     {  
  17.         (*_pCount)++;  
  18.     }  
  19.   
  20.     SharedArray<T> operator=(const SharedArray<T>& sp)  
  21.     {  
  22.         if (&s != this)  
  23.         {  
  24.             if (--(*pCount) == 0)  
  25.             {  
  26.                 delete _ptr;  
  27.                 _ptr = sp._ptr;  
  28.                 (*pCount)++;  
  29.             }  
  30.         }  
  31.         return *this;  
  32.     }  
  33.   
  34.     ~SharedArray()  
  35.     {  
  36.         if (_ptr)  
  37.         {  
  38.             if (--(*_pCount) == 0)  
  39.             {  
  40.                 delete _ptr;  
  41.                 delete _pCount;  
  42.                 _ptr = NULL;  
  43.                 _pCount = NULL;  
  44.             }  
  45.         }  
  46.     }  
  47.   
  48.     T* operator[](size_t index)  
  49.     {  
  50.         assert(index);  
  51.         return _ptr[index];  
  52.     }  
  53. private:  
  54.     T* _ptr;  
  55.     long *_pCount;  
  56. };  
  57.   
  58.   
  59. void Test()  
  60. {  
  61.     SharedArray<int> sp1(new int[10]);  
  62.     SharedArray<int> sp2(sp1);  
  63.     SharedArray<int> sp3 = sp1;  
  64. }  
  65.   
  66. int main()  
  67. {  
  68.     Test();  
  69.     system("pause");  
  70.     return 0;  
  71. }  
1
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:26589次
    • 积分:1897
    • 等级:
    • 排名:千里之外
    • 原创:154篇
    • 转载:25篇
    • 译文:0篇
    • 评论:0条
    文章分类