关键词搜索

源码搜索 ×
×

形象地聊聊C++中的浅拷贝与深拷贝

发布2014-11-08浏览7475次

详情内容

         先来看一个简单的程序:

 

  1. #include <iostream>
  2. using namespace std;
  3. class Point
  4. {
  5. public:
  6. int x;
  7. int y;
  8. Point(int xx, int yy)
  9. {
  10. x = xx;
  11. y = yy;
  12. }
  13. };
  14. int main()
  15. {
  16. Point A(1, 2);
  17. Point B(A); // 执行了编译器默认的浅拷贝
  18. cout << B.x << endl; // 1
  19. cout << B.y << endl; // 2
  20. return 0;
  21. }

      

 

       好, 继续看:

 

  1. #include <iostream>
  2. using namespace std;
  3. class Point
  4. {
  5. public:
  6. int x;
  7. int y;
  8. int* pTest;
  9. Point(int xx, int yy, int* p)
  10. {
  11. x = xx;
  12. y = yy;
  13. pTest = p;
  14. }
  15. };
  16. int main()
  17. {
  18. int m = 0;
  19. cout << &m << endl; // 0013FF7C
  20. Point A(1, 2, &m);
  21. cout << A.x << endl; // 1
  22. cout << A.y << endl; // 2
  23. cout << A.pTest << endl; // 0013FF7C
  24. Point B(A); // 执行了编译器默认的浅拷贝
  25. cout << B.x << endl; // 1
  26. cout << B.y << endl; // 2
  27. cout << B.pTest << endl; // 0013FF7C
  28. return 0;
  29. }

      由此可见, 浅拷贝就是浅浅的傻傻的拷贝。 上面这个程序会引出一个问题: 如果A.pTest指向了某一个堆, 那么B.pTest也指向了同一地方。 我们来看看:

 

 

  1. #include <iostream>
  2. using namespace std;
  3. class Point
  4. {
  5. public:
  6. int x;
  7. int y;
  8. int* pTest;
  9. Point(int xx, int yy)
  10. {
  11. x = xx;
  12. y = yy;
  13. pTest = new int(100);
  14. }
  15. };
  16. int main()
  17. {
  18. Point A(1, 2);
  19. cout << A.x << endl; // 1
  20. cout << A.y << endl; // 2
  21. cout << A.pTest << endl; // 00032738
  22. cout << *A.pTest << endl; // 100
  23. Point B(A); // 执行了编译器默认的浅拷贝
  24. cout << B.x << endl; // 1
  25. cout << B.y << endl; // 2
  26. cout << B.pTest << endl; // 00032738
  27. cout << *B.pTest << endl; // 100
  28. return 0;
  29. }

      显然, 如果析构, 则会有两次释放同一堆空间, 危险!!!看看这个危险的代码:

 

 

  1. #include <iostream>
  2. using namespace std;
  3. class Point
  4. {
  5. public:
  6. int x;
  7. int y;
  8. int* pTest;
  9. Point(int xx, int yy)
  10. {
  11. x = xx;
  12. y = yy;
  13. pTest = new int(100);
  14. }
  15. ~Point()
  16. {
  17. delete pTest;
  18. }
  19. };
  20. int main()
  21. {
  22. // 代码两次释放同一堆空间, 运行的时候出错
  23. Point A(1, 2);
  24. cout << A.x << endl; // 1
  25. cout << A.y << endl; // 2
  26. cout << A.pTest << endl; // 00032738
  27. cout << *A.pTest << endl; // 100
  28. Point B(A); // 执行了编译器默认的浅拷贝
  29. cout << B.x << endl; // 1
  30. cout << B.y << endl; // 2
  31. cout << B.pTest << endl; // 00032738
  32. cout << *B.pTest << endl; // 100
  33. return 0;
  34. }

      上面的代码不仅错误, 而且从逻辑上吧对象A和B无形地建立了关联, 显然是不合理的。

 

 

       看来, 编译器默认的拷贝构造函数是太肤浅了, 编译器不可能做那么多东西, 从逻辑上来讲,也无法做。 是该搞点深的了, 来看程序员自己需要写的深拷贝:

 

  1. #include <iostream>
  2. using namespace std;
  3. class Point
  4. {
  5. public:
  6. int x;
  7. int y;
  8. int* pTest;
  9. Point(int xx, int yy)
  10. {
  11. x = xx;
  12. y = yy;
  13. pTest = new int(100);
  14. }
  15. ~Point()
  16. {
  17. delete pTest;
  18. }
  19. Point(Point& P) // 不能是Point(Point P)
  20. {
  21. x = P.x;
  22. y = P.y;
  23. int value = *P.pTest;
  24. pTest = new int(value);
  25. }
  26. };
  27. int main()
  28. {
  29. Point A(1, 2);
  30. cout << A.x << endl; // 1
  31. cout << A.y << endl; // 2
  32. cout << A.pTest << endl; // 00032738
  33. cout << *A.pTest << endl; // 100
  34. Point B(A); // 执行了程序员自己写的深拷贝
  35. cout << B.x << endl; // 1
  36. cout << B.y << endl; // 2
  37. cout << B.pTest << endl; // 00030930
  38. cout << *B.pTest << endl; // 100
  39. return 0;
  40. }

      这就是深拷贝, 依靠程序员自己的实现, 撇清A对象和B对象的关系。

 

 

      来个形象的总结吧: 

      浅拷贝: 丈夫有100元, 取了个没有钱的妻子后, 自己与妻子共同掌管这100元, 花着花着, 有可能吵架呢偷笑
      深拷贝: 丈夫有100元, 取了个有100块钱的妻子后, 自己有100, 妻子有100,  各花各的, 互不干扰, 没有什么争吵大笑

 


 

 

      

 

相关技术文章

最新源码

下载排行榜

点击QQ咨询
开通会员
返回顶部
×
微信扫码支付
微信扫码支付
确定支付下载
请使用微信描二维码支付
×

提示信息

×

选择支付方式

  • 微信支付
  • 支付宝付款
确定支付下载