智能指针

梦里梦外; 2022-07-17 03:43 318阅读 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
  2. using namespace std;
  3. template<class T>
  4. class AutoPtr
  5. {
  6. public:
  7. AutoPtr(T* ptr = NULL)
  8. :_ptr(ptr)
  9. , _owner(true)
  10. {}
  11. AutoPtr(const AutoPtr& ap)
  12. :_ptr(ap._ptr)
  13. {
  14. ap._owner = false;
  15. _owner = true;
  16. }
  17. AutoPtr& operator=(const AutoPtr& ap)
  18. {
  19. if (&s != this)
  20. {
  21. delete _ptr;
  22. _ptr = ap._ptr;
  23. ap._owner = false;
  24. _owner = true;
  25. }
  26. return *this;
  27. }
  28. ~AutoPtr()
  29. {
  30. if (_ptr)
  31. {
  32. delete _ptr;
  33. _ptr = NULL;
  34. _owner = false;
  35. }
  36. }
  37. T* operator->()
  38. {
  39. return _ptr;
  40. }
  41. T& operator*()
  42. {
  43. return *_ptr;
  44. }
  45. private:
  46. T* _ptr;
  47. bool _owner;
  48. };
  49. void Test()
  50. {
  51. AutoPtr<int> ap1(new int(1));
  52. AutoPtr<int> ap2(ap1);
  53. AutoPtr<int> ap3 = ap1;
  54. }
  55. int main()
  56. {
  57. Test();
  58. system(“pause”);
  59. return 0;
  60. }

缺陷:

[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
  2. using namespace std;
  3. template<class T>
  4. class AutoPtr
  5. {
  6. public:
  7. AutoPtr(T* ptr)
  8. :_ptr(ptr)
  9. {}
  10. AutoPtr()
  11. :_ptr(NULL)
  12. {}
  13. AutoPtr(AutoPtr& ap) //权限转移
  14. : _ptr(ap._ptr)
  15. {
  16. ap._ptr = NULL;
  17. }
  18. AutoPtr& operator=(AutoPtr& ap)
  19. {
  20. if (&ap != this)
  21. {
  22. delete _ptr;
  23. _ptr = ap._ptr;
  24. ap._ptr = NULL; //权限转移
  25. }
  26. return *this;
  27. }
  28. ~AutoPtr()
  29. {
  30. if (_ptr)
  31. {
  32. delete _ptr;
  33. _ptr = NULL;
  34. }
  35. }
  36. T& operator*()
  37. {
  38. return *_ptr;
  39. }
  40. private:
  41. T* _ptr;
  42. };
  43. void Test()
  44. {
  45. AutoPtr<int> ap1(new int(2));
  46. AutoPtr<int> ap2 = ap1;
  47. AutoPtr<int> ap3(new int(3));
  48. ap3 = ap1;
  49. }
  50. int main()
  51. {
  52. Test();
  53. system(“pause”);
  54. return 0;
  55. }

二、ScopedPtr

这是最实用的智能指针。

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

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

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

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


[cpp] view plain copy

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

三、SharedPtr

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

[cpp] view plain copy

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

四、ScopedArray

ScopedArray与ScopedPtr区别在于:

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

[cpp] view plain copy

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

五、SharedPtr

同四。

[cpp] view plain copy

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

发表评论

表情:
评论列表 (有 0 条评论,318人围观)

还没有评论,来说两句吧...

相关阅读

    相关 智能指针

    智能指针 1.引入使用计数 定义智能指针的通用技术是采用一个使用计数。智能指针将一个计数器与类指向的对象相关联。使用计数跟踪该类有多少个对象共享同一指针。使用计数为0时

    相关 智能指针

    智能指针 智能指针的智能,体现在智能指针能够在每次完成工作之后自动释放占用的空间。 我们通常使用的裸指针,使用完成后需要通过delete或者free来进行释放,那么如

    相关 智能指针

    RAII(Resource Acquisition Is Initialization): 资源分配即初始化,定义封装一个类,用来实现调用构造函数时就可完成资源的分

    相关 智能指针

    在C++中,如果指针使用不当,比如没有及时释放指针所指向的内存,或者野指针等,会造成系统发生不可预估的错误,为了防止这一情况的发生,C++ STL提供了一系列智能指针类型 智

    相关 智能指针

    智能指针 在java中如果在堆上开辟内存是不需要手动释放的,我们叫做智能指针;但是在C++中如果用new在堆上开辟了空间,我们需要用delete进行手动释放,否则造