news 2026/10/31 7:08:53

C++深浅拷贝彻底讲透!90%新手崩溃的内存BUG根源

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
C++深浅拷贝彻底讲透!90%新手崩溃的内存BUG根源

深浅拷贝是 C++入门最大拦路虎,也是面试必考高频题。

很多新人写自定义类、动态内存,程序随机崩溃、双重释放、内存错乱,99% 的根源都是深浅拷贝没有搞懂。

一、什么是浅拷贝

如果你没有手动写拷贝构造函数、赋值运算符重载,编译器会默认帮你生成一份拷贝逻辑,这份默认逻辑就是浅拷贝。

浅拷贝行为:逐字节拷贝成员变量的值,不会单独分配堆内存

如果类里面有指针成员指向堆内存,拷贝之后,两个对象的指针,指向同一块堆地址。

带来两个致命问题:

1. 两个对象析构的时候,都会对同一个堆地址执行delete → 二次释放,程序直接崩溃

​

2. 一个对象修改堆里面的数据,另一个对象同步跟着被改动,数据互相干扰

浅拷贝复现代码(运行直接崩溃)

#include

#include

using namespace std;

class Person {

public:

char* name;

// 构造函数,堆上开辟内存存放名字

Person(const char* n) {

name = new char[strlen(n)+1];

strcpy(name, n);

}

// 析构,释放堆内存

~Person() {

delete[] name;

cout << "内存释放" << endl;

}

};

int main() {

Person p1("张三");

Person p2 = p1; // 调用编译器默认拷贝构造,浅拷贝!

// p1.name 和 p2.name 指向同一块堆内存

return 0;

// 函数结束,先销毁p2,释放内存;再销毁p1,再次释放同一块内存 → 崩溃

}

二、什么是深拷贝

深拷贝核心:拷贝的时候,重新开辟一块全新的堆内存,再把源数据复制过去

两个对象的内存完全独立,指针指向两块不同的堆空间,互不干扰。

析构的时候各自释放自己的内存,不会重复释放。

三、手写工业级深拷贝完整代码

#include

#include

using namespace std;

class Person {

public:

char* name;

// 构造函数

Person(const char* n) {

name = new char[strlen(n)+1];

strcpy(name, n);

}

// 深拷贝构造函数

Person(const Person& p) {

// 开辟新空间

name = new char[strlen(p.name)+1];

// 拷贝内容

strcpy(name, p.name);

cout << "执行深拷贝构造" << endl;

}

// 深拷贝赋值运算符重载

Person& operator=(const Person& p) {

// 防御自赋值:p = p 的情况,直接返回

if(this == &p) return *this;

// 先释放当前对象旧内存

delete[] name;

// 开辟新内存、拷贝数据

name = new char[strlen(p.name)+1];

strcpy(name, p.name);

return *this;

}

// 析构函数

~Person() {

delete[] name;

cout << "内存释放" << endl;

}

};

int main() {

Person p1("张三");

Person p2 = p1; // 调用我们手写的深拷贝构造

// 修改p2的名字,不会影响p1

p2.name[0] = '李';

cout << "p1名字:" << p1.name << endl; // 张三

cout << "p2名字:" << p2.name << endl; // 李四

return 0;

}

四、深浅拷贝一句话对比

浅拷贝:拷贝指针地址,多个对象共享同一份堆资源,危险,容易双重释放崩溃

深拷贝:拷贝数据内容,单独分配资源,对象内存完全独立,安全隔离

五、什么时候必须手动实现深拷贝?

只要你的自定义类里面包含指向堆内存的指针成员,就必须手动实现这三个函数,也就是C++经典三法则:

1. 拷贝构造函数

​

2. 赋值运算符重载 operator=

​

3. 析构函数

C++11之后还有移动语义,但是新手先吃透三法则。

六、常见拓展疑问

1. 为什么string、vector我们不用管深浅拷贝?

STL标准库的string、vector内部,已经封装好了深拷贝逻辑,编译器默认拷贝是安全的,不需要我们手动处理。

​

2. 如果类里面没有指针、没有堆资源,全部是普通内置成员(int、double),浅拷贝完全够用,不用自己写拷贝构造。

​

3. 移动语义和深浅拷贝是什么关系?

移动语义(move)是转移资源所有权,不拷贝数据,性能更高,是C++11为了优化大块内存拷贝新增的特性,属于深浅拷贝之后进阶内容。

七、工程避坑总结

1. 自定义类含有指针、堆资源,不要依赖编译器默认拷贝,默认一定是浅拷贝,埋下崩溃隐患;

​

2. 写赋值重载,第一句一定要判断自赋值,防止自己赋值自己导致提前释放内存;

​

3. 开发优先使用STL容器、string,尽量减少裸new、裸char*手动管理堆内存,从源头规避深浅拷贝BUG;

​

4. 面试手写深浅拷贝,自赋值判断是考官重点看的得分点,漏掉直接扣分。

吃透深浅拷贝,你就能解决新手阶段80%的内存随机崩溃问题。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/31 7:08:35

某东礼品卡程序绑定

声明 2766958292 本文章中所有内容仅供学习交流使用&#xff0c;不用于其他任何目的&#xff0c;抓包内容、敏感网址、数据接口 等均已做脱敏处理&#xff0c;严禁用于商业用途和非法用途&#xff0c;否则由此产生的一切后果均与作者无关&#xff01; 侵权通过头像私信或名字…

作者头像 李华
网站建设 2026/10/31 7:08:33

执行结果:结构智能中从方法输出到结构变化的闭环节点

执行结果&#xff1a;结构智能中从方法输出到结构变化的闭环节点——基于 WSaiOS-SI 执行结果理论的研究摘要&#xff1a; 传统程序语义通常将执行结果理解为函数返回值或最终输出&#xff0c;但在结构智能中&#xff0c;方法作用于对象、场景与环境后所产生的变化远不止一个值…

作者头像 李华
网站建设 2026/10/31 7:05:37

Windows 运维工具的技术实现逻辑

一、远程连接&#xff1a;SSH 会话保活与断线重连 会话为什么会掉。 最常见的原因不是网络断了&#xff0c;而是中间设备静默回收空闲连接——防火墙、NAT 网关为每条 TCP 连接维护状态表&#xff0c;超过 idle timeout&#xff08;常见 5 分钟&#xff09;没有报文经过就直接…

作者头像 李华
网站建设 2026/10/31 7:05:19

OpenAI 官方亲授:如何用 GPT-6 Astra 写出没有“AI味”的论文?

各位同仁好,我是七哥。一个在高校里从事人工智能 相关领域研究,钻研用大模型AI实操的学术人。可以和七哥交流学术写作或Gemini、GPT、Claude 等大模型 学术实操相关问题,多多交流,相互成就,共同进步。 AI写的论文为什么总有一股熟悉的机器味? OpenAI自己也注意到了,…

作者头像 李华
网站建设 2026/10/31 7:02:15

达梦数据库(DM)Linux 下创建新实例并预防 MySQL 迁移问题

达梦数据库&#xff08;DM&#xff09;Linux 下创建新实例并预防 MySQL 迁移问题适用场景&#xff1a;宿主机已存在一个达梦实例&#xff08;示例&#xff1a;/opt/dmdbms/data/DMDB&#xff0c;端口 5236&#xff09;&#xff0c;需要在不影响老实例的前提下新建一个实例&…

作者头像 李华