当前位置:   article > 正文

深拷贝(C++基础)

深拷贝(C++基础)

字符串、指针或者带有指针的对象拷贝的时候,如果只是简单做了赋值处理,不能拷贝一份指针指向的内存地址,只是拷贝了一份指向内存地址的指针,在对拷贝过的内存操作的时候就很可能带来一些错误,比如释放了拷贝过的内存,之前拷贝前的内存也会被释放,因为根本是同一个内存地址。 

下面是一个基本类型的案例:

  1. struct Vector2 {
  2. float x, y;
  3. Vector2(float x, float y) :x(x), y(y) {}
  4. };
  5. int main() {
  6. Vector2* a = new Vector2(1.0f,2.0f);
  7. Vector2* b = a;
  8. b->x = 3.0f;
  9. std::cout << a->x << std::endl;
  10. std::cout << b->y << std::endl;
  11. std::cout << b->x << std::endl;
  12. }

可以看出,通过赋值后的指针指向,正常修改其指向值,复制对象指针指向的值也会被修改,因为在赋值时,只复制了指针,并没有赋值指向对象,下面通过一个字符串的例子进一步说明:

手写一个string类,

  1. class String {
  2. private:
  3. char* m_Buffer;
  4. unsigned int m_Size;
  5. public:
  6. String(const char* string) {
  7. m_Size = strlen(string);
  8. m_Buffer = new char[m_Size + 1];
  9. //需要算上终止符,加上1的长度,也可以使用strcpy函数,拷贝时会包含空终止符
  10. /*for (int i = 0; i < m_Size;i++) {
  11. m_Buffer[i] = string[i];
  12. }*/
  13. memcpy(m_Buffer, string, m_Size + 1);
  14. //目的、来源、大小,少写了一个\0终止符
  15. m_Buffer[m_Size] = 0;//手动加上终止符
  16. }
  17. ~String() {
  18. delete[] m_Buffer;
  19. }
  20. friend std::ostream& operator<<(std::ostream& stream, const String& string);//友元
  21. };
  22. void PrintString(String string) {
  23. std::cout << string << std::endl;
  24. }
  25. int main() {
  26. String string = "lhx";
  27. String second = string;
  28. //浅拷贝,因为复制的指针,而指针作用的是同一片内存空间
  29. //解决办法,深拷贝:拷贝构造函数
  30. second[1] = 'v';
  31. PrintString(string);
  32. PrintString(second);
  33. std::cin.get();
  34. }

second[1] = 'v';报错,因为没有对string类进行[]重载,并不能完成中括号数组的操作,在类中加上如下代码完成对[]的重载:

  1. char& operator[](unsigned int index) {
  2. return m_Buffer[index];
  3. }

运行后发现,输出都是lvx,并且在程序结束的时候会出线错误,说明lhx只有一个,并且被修改为lvx,而出现错误是因为在使用析构函数进行释放内存的时候,同一片内存被连续释放了。

 所以需要重写深拷贝构造方法,在类中加入如下代码:

  1. String(const String& other) :m_Size(other.m_Size) {
  2. std::cout << "deep copy" << std::endl;
  3. m_Buffer = new char[m_Size + 1];
  4. memcpy(m_Buffer, other.m_Buffer, m_Size + 1);
  5. }//深拷贝使用代码

发现被连续copy操作被连续调用,但不再出现错误:

为解决连续调用问题,对以下代码重写:

  1. void PrintString(const String& string) {
  2. std::cout << string << std::endl;
  3. }

要习惯总是通过const引用去传递对象,但在某些情况下,复制可能更快。

如果不带const,可以将临时的右值传递到实际函数,这个以后再说~

以下为全部代码:

  1. #include<iostream>
  2. #include<string>
  3. struct Vector2 {
  4. float x, y;
  5. Vector2(float x, float y) :x(x), y(y) {}
  6. };
  7. class String {
  8. private:
  9. char* m_Buffer;
  10. unsigned int m_Size;
  11. public:
  12. String(const char* string) {
  13. m_Size = strlen(string);
  14. m_Buffer = new char[m_Size + 1];//需要算上终止符,加上1的长度,也可以使用strcpy函数,拷贝时会包含空终止符
  15. /*for (int i = 0; i < m_Size;i++) {
  16. m_Buffer[i] = string[i];
  17. }*/
  18. memcpy(m_Buffer, string, m_Size + 1);//目的、来源、大小,少写了一个\0终止符
  19. m_Buffer[m_Size] = 0;//手动加上终止符
  20. }
  21. //String(const String& other) :m_Buffer(other.m_Buffer), m_Size(other.m_Size) {}
  22. //String(const String& other) {
  23. // memcpy(this, &other, sizeof(String));
  24. //}
  25. //String(const String& other) = delete;
  26. String(const String& other) :m_Size(other.m_Size) {
  27. std::cout << "deep copy" << std::endl;
  28. m_Buffer = new char[m_Size + 1];
  29. memcpy(m_Buffer, other.m_Buffer, m_Size + 1);
  30. }//深拷贝使用代码
  31. ~String() {
  32. delete[] m_Buffer;
  33. }
  34. char& operator[](unsigned int index) {
  35. return m_Buffer[index];
  36. }
  37. friend std::ostream& operator<<(std::ostream& stream, const String& string);//友元
  38. };
  39. std::ostream& operator<<(std::ostream& stream, const String& string) {
  40. //stream << string.m_Buffer();
  41. stream << string.m_Buffer;
  42. return stream;
  43. }
  44. void PrintString(const String& string) {
  45. std::cout << string << std::endl;//如果不带const,可以将临时的右值传递到实际函数
  46. //总是通过const引用去传递对象,在某些情况下,复制可能更快
  47. }
  48. //void PrintString(String string) {
  49. // std::cout << string << std::endl;
  50. //}
  51. int main() {
  52. String string = "lhx";
  53. String second = string;//浅拷贝,因为复制的指针,而指针作用的是同一片内存空间
  54. //解决办法,深拷贝:拷贝构造函数
  55. second[1] = 'v';
  56. PrintString(string);
  57. PrintString(second);
  58. std::cin.get();
  59. }

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

闽ICP备14008679号