深拷贝和浅拷贝

文章详细介绍了C++中的拷贝构造函数,包括默认的浅拷贝和自定义的深拷贝。浅拷贝可能导致资源重复释放的问题,而深拷贝通过在堆区重新申请空间避免了这一问题。当类成员包含指针或堆内存时,必须提供自定义的拷贝构造函数以防止浅拷贝引发的错误。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  深浅拷贝问题是面试经典问题,今天我们来全面认识一下。

       C++中的构造函数有三类:默认构造函数,有参构造函数,拷贝构造函数。

前两种构造函数主要用于默认值对成员变量进行初始化或者是传递指定参数对成员变量进行出初始化,而拷贝构造函数是用一个已经定义的对象进行拷贝。

       认识浅拷贝:如果类当中没有定义拷贝构造函数,则会调用默认的拷贝构造函数。默认的拷贝构造函数中会对对象中的变量进行简单的赋值拷贝操作,就是调用等号进行赋值,这就是浅拷贝。

       认识深拷贝:深拷贝就是在堆区重新申请一块空间来存放自己的数据。

       简单的文字解释很难对深浅拷贝有较深的理解下面那我们看两个实例。

首先是浅拷贝的实例:

这里我们可以看出来调用了两次析构函数说明b对象拷贝a对象成功,并且最后还成功释放了资源。

继续看下一个例子:

当类成员变量中含有指针或者引用,将变量定义在堆区,此时继续使用默认的拷贝构造函数对a进行拷贝是否还会像之前那样成功?

结果发现程序崩溃了。

为什么会发生崩溃,我们来分析一下,首先我们的对象a实例化时会调用含参构造函数进行初始化,初始化过程中会向堆区申请空间,并且指针变量ptr还会指向申请的空间,接着我们创建b、对象并且调用默认的拷贝构造函数对b进行初始化此时会发生下面的情况

两个指针指向同一块堆区的空间,这就会导致在调用析构函数时候会出现重复释放同一块内存空间的问题。这就是浅拷贝典型的问题。由于编译器默认的拷贝构造函数就是浅拷贝,所以我们需要重新定义拷贝构造函数。

重新申请一块堆空间存放数据。

这样就不会出现像浅拷贝那样重复释放空间的问题。

总结:浅拷贝就是编译器实现的直接等号复制操作,深拷贝重新申请一块空间,进行拷贝操作,所以如果对象中有属性在堆区中开辟的,一定要自己提供拷贝构造函数,防止浅拷贝带来的问题。

<think>嗯,用户想了解C++中的深拷贝浅拷贝的区别以及实现方法。首先,我需要回忆一下这两个概念的基本定义。浅拷贝应该是指简单的复制指针,导致两个对象指向同一块内存,而深拷贝则是复制指针所指向的数据本身,这样两个对象就独立了。 根据用户提供的引用内容,引用[1]里提到浅拷贝只拷贝指针,深拷贝会拷贝内容,默认的拷贝构造函数是浅拷贝,需要自己实现深拷贝。引用[2][3]给出了具体的代码示例,展示了如何通过自定义拷贝构造函数来实现深拷贝,比如在Person类中为Name或m_height重新分配内存并复制数据。引用[4]中的Array类也演示了类似的深拷贝实现,即在拷贝构造函数中新建内存空间并复制数据。 接下来,我需要将这些信息组织成一个清晰的回答。首先解释两者的区别,用比喻的话,浅拷贝像快捷方式,深拷贝像复制文件,这样用户容易理解。然后,说明默认拷贝构造函数的问题,比如会导致重复释放内存,出现错误。接着,用用户提供的代码例子来说明如何手动实现深拷贝,比如在拷贝构造函数中分配新内存,并复制数据。可能还需要提到析构函数的重要性,确保深拷贝的对象能正确释放内存。 用户可能还关心什么时候需要深拷贝,应该是在类中有指针成员指向动态分配的内存时。这时候必须自己实现深拷贝,否则会出现问题。同时,需要注意在实现深拷贝时,除了拷贝构造函数,可能还需要重载赋值运算符,但用户的问题可能没有提到,所以可能暂时不需要展开,但如果有相关问题可以提到。 最后,生成的相关问题需要围绕实现深拷贝的方法、常见错误场景以及如何避免等问题。这样用户如果有进一步的问题,可以继续查阅相关内容。确保回答中正确引用提供的资料,比如引用[1]、[3]中的例子来说明浅拷贝的问题深拷贝的实现步骤。</think>### C++深拷贝浅拷贝的区别及实现方式 #### 一、核心概念 1. **浅拷贝** - 仅复制对象的指针成员变量,拷贝后新旧对象的指针**指向同一块内存地址**,例如: ```cpp //示例代码片段 m_height = p.m_height; //浅拷贝直接复制指针[^3] ``` - 类似文件快捷方式,多个指针共享同一资源,可能导致**重复释放内存**的崩溃问题[^1] 2. **深拷贝** - 为指针成员**创建独立的内存空间**,完全复制原对象的数据内容: ```cpp m_height = new int(*p.m_height); //新建堆空间并复制数据[^3] ``` - 类似完整文件复制,新旧对象完全独立,避免资源冲突[^1] #### 二、实现方式对比 | 特征 | 浅拷贝 | 深拷贝 | |--------------|---------------------------|---------------------------| | 内存分配 | 共享原对象内存 | 新建独立内存空间 | | 实现复杂度 | 编译器默认提供 | 需手动实现拷贝构造函数 | | 资源管理风险 | 易出现重复释放 | 内存管理安全 | | 典型应用场景 | 无指针成员的简单对象 | 包含指针/动态资源的对象 | #### 三、关键实现步骤(以类`person`为例) 1. **定义深拷贝构造函数** ```cpp person(const person& p) { m_age = p.m_age; m_height = new int(*p.m_height); //关键:新建堆内存并复制数据 } ``` 2. **配套析构函数** ```cpp ~person() { delete m_height; //确保正确释放深拷贝分配的内存 m_height = nullptr; } ``` 3. **错误示例(浅拷贝陷阱)** 若直接使用默认拷贝构造函数: ```cpp person p2(p1); //此时p2.m_height与p1.m_height指向同一地址 ``` 析构时会导致**重复释放同一内存地址**,引发程序崩溃[^1] #### 四、应用场景分析 - **必须使用深拷贝**:类包含指针成员且指向动态分配内存时(如字符串、数组等) - **可使用浅拷贝**:仅包含基本数据类型或没有资源所有权的指针时 - **典型案例**:自定义容器类(如动态数组`Array`类[^4])、包含文件句柄的类
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

带点脑子~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值