当前位置:   article > 正文

String类的浅拷贝、深拷贝、引用计数、写时拷贝_std::string的拷贝复制是基于引用计数的浅拷贝,因此它们指向相同的数据地址

std::string的拷贝复制是基于引用计数的浅拷贝,因此它们指向相同的数据地址
皆以s2=s1为例

浅拷贝:只是直接将s1的值拷贝过来,s1、s2共用同一块内存。

  1. class String
  2. {
  3. public:
  4. String(const char* str)
  5. :_str(new char[strlen(str) + 1])
  6. {
  7. strcpy(_str, str);
  8. }
  9. String(const String& s)
  10. :_str(s._str)
  11. {}
  12. String& operator=(const String& s)
  13. {
  14. if (this != &s)
  15. {
  16. _str = s._str;
  17. }
  18. return *this;
  19. }
  20. ~String()
  21. {
  22. if (_str)
  23. {
  24. cout << "delete" << endl;
  25. delete[] _str;
  26. }
  27. }
  28. private:
  29. char* _str;
  30. };
  31. void TestString()
  32. {
  33. String s1("bigbang");
  34. String s2(s1);
  35. String s3("12345");
  36. s3 = s1;
  37. }
  38. int main()
  39. {
  40. TestString();
  41. system("pause");
  42. return 0;
  43. }
缺陷是调用析构函数时一块内存会被多次释放,导致程序崩溃。


深拷贝:在拷贝构造时开辟了空间,s1、s2各占有一块内存,无论析构多少次程序都不会崩溃。

  1. //深拷贝传统写法
  2. class String
  3. {
  4. public:
  5. String(char* str = "")
  6. :_str(new char[strlen(str) + 1])
  7. {
  8. strcpy(_str, str);
  9. }
  10. String(const String& s)
  11. :_str(new char[strlen(s._str) + 1])
  12. {
  13. strcpy(_str, s._str);
  14. }
  15. //String& operator=(const String& s) //缺陷:new开辟空间可能会失败,s1将会被破坏
  16. //{
  17. // if (this != &s)
  18. // {
  19. // delete[] _str;
  20. // _str = new char[strlen(s._str) + 1];
  21. // strcpy(_str, s._str);
  22. // }
  23. // return *this;
  24. //}
  25. String& operator=(const String& s) //解决了上述缺陷
  26. {
  27. if (this != &s)
  28. {
  29. char* tmp = new char[strlen(s._str) + 1];
  30. strcpy(tmp, s._str);
  31. delete[] _str;
  32. _str = tmp;
  33. }
  34. return *this;
  35. }
  36. ~String()
  37. {
  38. if (_str)
  39. {
  40. cout << "delete" << endl;
  41. delete[] _str;
  42. _str = NULL;
  43. }
  44. }
  45. private:
  46. char* _str;
  47. };
  48. void TestString()
  49. {
  50. String s1("bigbang");
  51. String s2(s1);
  52. }
  53. int main()
  54. {
  55. TestString();
  56. system("pause");
  57. return 0;
  58. }

  1. //深拷贝现代写法:只在构造函数中new,只在析构函数中delete,可维护性变强
  2. class String
  3. {
  4. public:
  5. String(char* str = "")
  6. :_str(new char[strlen(str) + 1])
  7. {
  8. strcpy(_str, str);
  9. }
  10. String(const String& s)
  11. :_str(NULL)
  12. {
  13. String tmp(s._str); //调用构造函数开辟临时空间,交换后可把原来的空间释放掉
  14. swap(_str, tmp._str);
  15. }
  16. String& operator=(const String& s)
  17. {
  18. if (_str != s._str)
  19. {
  20. String tmp(s);
  21. swap(_str, tmp._str);
  22. }
  23. return *this;
  24. }
  25. //String& operator=(String s) //针对已经存在的两个对象
  26. //{
  27. // swap(_str, s._str);
  28. // return *this;
  29. //}
  30. ~String()
  31. {
  32. if (_str)
  33. {
  34. cout << "delete" << endl;
  35. delete[] _str;
  36. _str = NULL;
  37. }
  38. }
  39. private:
  40. char* _str;
  41. };
  42. void TestString()
  43. {
  44. String s1("bigbang");
  45. String s2(s1);
  46. String s3;
  47. s3 = s1;
  48. }
  49. int main()
  50. {
  51. TestString();
  52. system("pause");
  53. return 0;
  54. }

在引用计数中,每一个对象负责维护对象所有引用的计数值。当一个新的引用指向对象时,引用计数器就递增,当去掉一个引用时,引用计数就递减。当引用计数到零时,该对象就将释放占有的资源。

  1. class String
  2. {
  3. public:
  4. String(char* str = "")
  5. :_str(new char[strlen(str) + 1])
  6. , _refCount(new int(1))
  7. {
  8. strcpy(_str, str);
  9. }
  10. String(const String& s)
  11. :_str(s._str)
  12. , _refCount(s._refCount)
  13. {
  14. ++(*_refCount);
  15. }
  16. String& operator=(const String& s)
  17. {
  18. // 1.s1和s2是否指向同一块空间
  19. // 2.减减s1指向空间的引用计数,如s1是最后一块管理对象,则释放
  20. if (_str != s._str)
  21. {
  22. this->Release();
  23. _str = s._str;
  24. _refCount = s._refCount;
  25. ++(*_refCount);
  26. }
  27. return *this;
  28. }
  29. String& operator=(String s) //s是临时开辟出来的一块空间,出了函数会自动释放
  30. {
  31. swap(_str, s._str);
  32. swap(_refCount, s._refCount); //交换后引用计数不改变
  33. return *this;
  34. }
  35. ~String()
  36. {
  37. Release();
  38. }
  39. void Release()
  40. {
  41. if (--(*_refCount) == 0)
  42. {
  43. cout << "delete" << endl;
  44. delete[] _str;
  45. delete _refCount; //注意delete的格式和new的格式对齐
  46. }
  47. }
  48. private:
  49. char* _str;
  50. int* _refCount;
  51. };
  52. void TestString()
  53. {
  54. String s1("bigbang");
  55. String s2(s1);
  56. String s3;
  57. s3 = s1;
  58. }
  59. int main()
  60. {
  61. TestString();
  62. system("pause");
  63. return 0;
  64. }

  1. //引用计数的浅拷贝--现代写法+写时拷贝:指用浅拷贝的方法拷贝其他对象,多个指针指向同一块空间,
  2. //只有当对其中一个对象修改时,才会开辟一个新的空间给这个对象,和它原来指向同一空间的对象不会受到影响。
  3. class String
  4. {
  5. public:
  6. String(char* str = "")
  7. :_str(new char[strlen(str) + 1])
  8. , _refCount(new int(1))
  9. {
  10. strcpy(_str, str);
  11. }
  12. String(const String& s)
  13. :_str(s._str)
  14. , _refCount(s._refCount)
  15. {
  16. ++(*_refCount);
  17. }
  18. String& operator=(const String& s)
  19. {
  20. if (_str != s._str)
  21. {
  22. this->Release();
  23. _str = s._str;
  24. _refCount = s._refCount;
  25. ++(*_refCount);
  26. }
  27. return *this;
  28. }
  29. String& operator=(String s)
  30. {
  31. swap(_str, s._str);
  32. swap(_refCount, s._refCount);
  33. return *this;
  34. }
  35. void Release()
  36. {
  37. if (--(*_refCount) == 0)
  38. {
  39. cout << "delete" << endl;
  40. delete[] _str;
  41. delete _refCount;
  42. }
  43. }
  44. ~String()
  45. {
  46. Release();
  47. }
  48. char& operator[](size_t index)
  49. {
  50. CopyOnWrite();
  51. assert(index < strlen(_str));
  52. return _str[index];
  53. }
  54. const char& operator[](size_t index) const
  55. {
  56. assert(index < strlen(_str));
  57. return _str[index];
  58. }
  59. void CopyOnWrite()
  60. {
  61. if (*_refCount > 1)
  62. {
  63. char* tmp = new char[strlen(_str) + 1];
  64. strcpy(tmp, _str);
  65. --(*_refCount);
  66. _refCount = new int(1);
  67. _str = tmp;
  68. }
  69. }
  70. private:
  71. char* _str;
  72. int* _refCount;
  73. };
  74. void Fun(const String& s)
  75. {
  76. cout << s[4] << endl;
  77. }
  78. void TestString()
  79. {
  80. String s1("bigbeng");
  81. String s2(s1);
  82. String s3 = s2;
  83. Fun(s1);
  84. s1[4] = 'a';
  85. cout << s1[4] << endl;
  86. }
  87. int main()
  88. {
  89. TestString();
  90. system("pause");
  91. return 0;
  92. }





声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/501728
推荐阅读
相关标签
  

闽ICP备14008679号