C++深拷贝与浅拷贝的区别-简单易懂

介绍

浅拷贝就比如像引用类型,而深拷贝就比如值类型。
浅拷贝是指源对象与拷贝对象共用一份实体,仅仅是引用的变量不同(名称不同)。对其中任何一个对象的改动都会影响另外一个对象。举个例子,一个人一开始叫张三,后来改名叫李四了,可是还是同一个人,不管是张三缺胳膊少腿还是李四缺胳膊少腿,都是这个人倒霉。
深拷贝是指 源对象与拷贝对象互相独立 ,其中任何一个对象的改动都不会对另外一个对象造成影响。举个例子,一个人名叫张三,后来用他克隆(假设法律允许)了另外一个人,叫李四,不管是张三缺胳膊少腿还是李四缺胳膊少腿都不会影响另外一个人。比较典型的就是Value(值)对象,如预定义类型Int32,Double,以及结构(struct),枚举(Enum)等。

浅拷贝

浅拷贝就是对象的数据成员之间的简单赋值, 如你设计了一个没有类而没有提供它的复制构造函数,当用该类的一个对象去给令一个对象赋值时所执行的过程就是浅拷贝,如:

#include <iostream>
using namespace std;
class A
{
public:A(int _data) : data(_data){}int GetX() {return data;}A() {}
private:int data;
};
int main()
{A a(5);A b;b = a;cout << b.GetX() << endl;return 0;
}

运行结果为 5. 这就是一个浅拷贝的过程。
如果对象中没有其他的资源(如:堆,文件,系统资源等),则深拷贝和浅拷贝没有什么区别,
但当对象中有这些资源时,例子:

#include <iostream>
using namespace std;
class A
{
public:A() {}A(int _size) : size(_size) { data = new int[size]; *data = 5;} ~A() {delete[] data;data = nullptr; } int Get_Val() {return *data;}int *Get_Val_add() { return data; }
private:int *data;int size;
};
int main()
{A a(5);A b(a);cout << b.Get_Val() << endl;return 0;
}

因为类A中的复制构造函数是编译器生成的,所以A b(a)执行一个浅拷贝过程,浅拷贝只是对象数据之间的简单赋值 (如:b.size = a.size, b.data = a.data)
这里b的指针data 和a的指针指向了堆上的同一块内存,a和b析构时,b先把其data指向的动态分配的内存释放了一次,而后a析构时又将这块已经释放过的内存再释放一次。
对同一块内存释放执行2次及2次以上的释放会造成内存泄露或者是程序crash!

深拷贝

需要用 深拷贝 来解决上述问题:
深拷贝就是当拷贝对象中有对其他资源(如堆、文件、系统等)的引用时(引用可以是指针或引用)时,对象的另开辟一块新的资源,而不再对拷贝对象中有对其他资源的引用的指针或引用进行单纯的赋值。

#include <iostream>
using namespace std;
class A
{
public:A() {}A(int _size) : size(_size) { data = new int[size]; *data = 5;} A( const A& _A) : size(_A.size) //深拷贝{ data = new int[size];*data = *_A.data;} ~A() {delete[] data;data = nullptr; } int Get_Val() {return *data;}int *Get_Val_add() { return data; }
private:int *data;int size;
};
int main()
{A a(5);A b(a);cout << b.Get_Val() << endl;return 0;
}

总结

深拷贝和浅拷贝的区别是在对象状态中包含其它对象的引用的时候,当拷贝一个对象时,如果需要拷贝这个对象引用的对象,则是深拷贝,否则是浅拷贝。

拷贝构造函数经常用在一个对象对另一个对象初始化的情况,如果使用默认的拷贝构造函数,用一个对象初始化另外一个对象的,C++会进行简单的成员变量之间的赋值,假如对象有申请内存的行为,被初始化的对象的内存地址会被赋值为初始化对象的内存地址,这样一来,两个对象拥有相同的内存地址,一旦其中有一个对象析构的时候,释放了内存。另外一个对象析构的时候,会释放已经释放了的内存,导致了内存的多次释放,出现段错误。

还有一种情况是,一个对象直接给另外一个对象使用“=”进行赋值操作,对于这种情况C++也会采取简单的成员变量直接的赋值操作,这样会导致两个问题:

  1. 跟上面的问题一样,对象被析构的时候会导致同一内存的多次释放,引发段错误;

  2. 被赋值对象之前申请的内存地址被赋值对象的内存地址替换,没有得到释放,引发内存泄漏。

深拷贝与浅拷贝可以这样理解:如果一个类拥有内存资源,当这个类的对象发生复制过程的时候,内存资源重新分配,这个过程就是深拷贝,反之,没有重新分配内存资源,而是对象间的内存地址复制,就是浅拷贝。

解决调用拷贝构造函数导致的浅拷贝问题的方法是自定义拷贝构造函数,在拷贝构造函数中不进行内存地址的直接赋值,而是重新为对象分配内存空间。而解决“=”赋值操作引发的浅拷贝问题的方法是采用运算符重载解决。

参考:

https://blog.csdn.net/joshgu958/article/details/35302413?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-4.control&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-4.control

https://blog.csdn.net/weicao1990/article/details/81632832

C++深拷贝与浅拷贝的区别-简单易懂相关推荐

  1. 【C++面试问答】搞清楚深拷贝与浅拷贝的区别

    问题 深拷贝和浅拷贝的区别是面试中的常见问题之一,对于不同的编程语言,这个问题的回答可能稍有差别,下面我们就来探索一下它们之间的异同吧. 先来看看在JavaScript对象的深拷贝与浅拷贝的区别: 浅 ...

  2. 如何完美解答面试问题——深拷贝和浅拷贝的区别

    大家好,我是孤焰.今天要谈一谈在面试过程中可能被面试官提到的一个问题--深拷贝和浅拷贝的区别? 由于我也是刚刚学习编程的小白,所以此篇博文将参考了多篇博文,最后总结而成. 最近由于多门考试临近,所以博 ...

  3. java -- 深拷贝和浅拷贝的区别 如何实现深拷贝和浅拷贝

    文章目录 1. 深拷贝和浅拷贝的区别 1.1 浅拷贝实例 1.1.1 测试1 直接赋值 1.1.2 测试2 改变源对象的值 1.2 深拷贝实例 `这是用于深拷贝的测试类` 1.2.1 方法一: 构造函 ...

  4. js深拷贝和浅拷贝的区别

    js深拷贝和浅拷贝的区别 如何来区分深拷贝和浅拷贝,其实简单,例如: 就是我声明一个obj对象,如何让var a直接等于obj,然后有在obj新增个fun,此时的a也会随着新增个fun,相同a新增数据 ...

  5. Python基础:对象的深拷贝和浅拷贝的区别

    Python基础:对象的深拷贝和浅拷贝的区别 1 变量与对象 2 不可变对象与可变对象 3 直接赋值 4 浅拷贝 5 深拷贝 参考文献 1 变量与对象 对象:内存中存储数据的实体,有明确的类型.在Py ...

  6. python 深拷贝_详解python的复制,深拷贝和浅拷贝的区别

    概述 今天主要来看看Python中的浅拷贝和深拷贝内容,这里用一个实例来说明~ 需求: 将一个列表的数据复制到另一个列表中. 思路: 使用列表[:],拿不准可以调用copy模块. 实现方法: #!/u ...

  7. c++深拷贝和浅拷贝的区别?

    c++深拷贝和浅拷贝的区别 浅拷贝 深拷贝 总结 浅拷贝 对一个已知对象进行拷贝,编译系统会自动调用一种构造函数--拷贝构造函数,如果用户未定义拷贝构造函数,则会调用默认拷贝构造函数,调用一次构造函数 ...

  8. Python中深拷贝与浅拷贝的区别?

    往期面试题: 列举Python中的标准异常类? 说说Python面向对象三大特性? 说说Python中有几种数据类型? 说说Python模块主要分哪三类? 废话不多说,开始今天的题目: 问:说说Pyt ...

  9. python的复制,深拷贝和浅拷贝的区别

    python的复制,深拷贝和浅拷贝的区别 在python中,对象赋值实际上是对象的引用.当创建一个对象,然后把它赋给另一个变量的时候,python并没有拷贝这个对象,而只是拷贝了这个对象的引用 一般有 ...

最新文章

  1. [铁道部信息化管理]号外
  2. 一些计算机知识的总结(转)
  3. C语言实验 圆周率1193,【圆周率】小数点后10000位,4个4个分,你能找到那些配对?...
  4. boost::push_front相关的测试程序
  5. .net core webapi 前后端开发分离后的配置和部署
  6. 云上自动化:云上编排让上云更简单
  7. linux7添加端口过程,CentOS7安装firewalld防火墙添加放行端口简单演示过程
  8. Qt——菜单栏、工具栏、状态栏
  9. mysql优化--避免数据类型的隐式转换
  10. js特效之上下翻页相册效果
  11. CC2530概述(简单了解)
  12. Java实现微信轰炸
  13. 【jzoj5053】【石子游戏】【搜索】
  14. delphi过时了吗?王者归来!从Pascal到Embarcadero Delphi 10.4.1的发展历史回顾
  15. 光纤存储服务器虚拟化,光纤存储DELL MD3600连接VMware ESX 65
  16. Bezier曲线及其de casteljau算法 matlab实现
  17. 如何查看别人网站的访问量
  18. java企业工程项目管理系统平台源码(三控:进度组织、质量安全、预算资金成本、二平台:招采、设计管理)
  19. 配置静态NAT和配置动态NAT
  20. 【matlab教程】02、拼接矩阵或向量

热门文章

  1. java实现csv导入pg数据库
  2. 【论文精读】NeRF —— 解读《NeRF: Representing Scenes as Neural Radiance Fields for View Synthesis》
  3. 三相异步电机检测技术的应用研究
  4. 卸载oracle10g服务端,oracle10g数据库服务器的安装与卸载.ppt
  5. 基于位表示的8叉树数据存储原理
  6. SecureCRT复制粘贴快捷键
  7. 区块链分类与技术特点
  8. 一个文本翻译工具的实现
  9. opencv学习四:色彩空间转换
  10. 鸟笼山剿匪记(爆笑)4铃声 鸟笼山剿匪记(爆笑)4手机铃声免...