news 2026/4/22 12:47:13

C++ 赋值运算符重载:深拷贝 vs 浅拷贝的生死线!

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
C++ 赋值运算符重载:深拷贝 vs 浅拷贝的生死线!

🔄 C++ 赋值运算符重载:深拷贝 vs 浅拷贝的生死线!

大家好!今天我们来聊一个 C++ 中极易被忽视、却可能引发严重 bug 的知识点——赋值运算符operator=的重载

你可能写过a = b,但当你的类中包含指向堆内存的指针时,这个看似简单的等号,就可能让你的程序崩溃、内存泄漏,甚至“神秘地”修改不该改的数据!

别慌,今天我们就用一段经典示例,彻底搞懂为什么需要重载赋值运算符,以及如何正确实现深拷贝


🧠 编译器默认给你的 4 个函数

在 C++ 中,即使你什么都没写,编译器也会悄悄为你的类生成以下 4 个函数:

  1. 默认构造函数(无参,空实现)

  2. 默认析构函数(无参,空实现)

  3. 默认拷贝构造函数(逐成员值拷贝)

  4. **默认赋值运算符operator=**(也是逐成员值拷贝)

⚠️ 问题来了:“值拷贝”对指针来说,就是“浅拷贝”


💥 浅拷贝的灾难:多个对象共用一块堆内存

来看你写的Person类(代码原样保留,未作任何修改):

class Person { public: Person(int age) { // 将年龄数据开辟到堆区 m_Age = new int(age); } // 重载赋值运算符 Person& operator=(Person &p) { if (m_Age != NULL) { delete m_Age; m_Age = NULL; } // 编译器提供的代码是浅拷贝 // m_Age = p.m_Age; // 提供深拷贝 解决浅拷贝的问题 m_Age = new int(*p.m_Age); // 返回自身 return *this; } ~Person() { if (m_Age != NULL) { delete m_Age; m_Age = NULL; } } // 年龄的指针 int *m_Age; };

如果不重载operator=,会发生什么?

假设使用默认赋值:

p2 = p1; // 默认:m_Age = p1.m_Age (浅拷贝!)

结果:

  • p1.m_Agep2.m_Age指向同一块堆内存

  • p1p2析构时,delete这块内存

  • 另一个对象再访问或析构 →野指针 / 重复释放 → 程序崩溃

这就是典型的浅拷贝陷阱


✅ 正确做法:手动实现深拷贝

你的重载版本完美解决了这个问题:

Person& operator=(Person &p) { if (m_Age != NULL) { delete m_Age; m_Age = NULL; } m_Age = new int(*p.m_Age); // 深拷贝:新开内存,复制值 return *this; }

关键步骤:

  1. 先释放自身原有堆内存(防止内存泄漏)

  2. 从源对象的堆数据中读取值,重新 new 一块新内存

  3. 返回*this的引用,支持链式赋值(如p3 = p2 = p1


🧪 测试效果

void test01() { Person p1(18); Person p2(20); Person p3(30); p3 = p2 = p1; // 链式赋值 cout << "p1的年龄为:" << *p1.m_Age << endl; cout << "p2的年龄为:" << *p2.m_Age << endl; cout << "p3的年龄为:" << *p3.m_Age << endl; }

输出:

p1的年龄为:18 p2的年龄为:18 p3的年龄为:18

✅ 三个对象各自拥有独立的堆内存,互不影响!
✅ 支持p3 = p2 = p1链式赋值(因为返回了*this引用)!


📌 黄金法则:三/五法则(Rule of Three/Five)

如果你的类中:

  • 使用了动态内存(如new

  • 或管理了其他资源(文件句柄、socket 等)

那么你很可能需要同时自定义

  • 析构函数

  • 拷贝构造函数

  • 赋值运算符

这就是著名的“三法则”(C++11 后扩展为“五法则”,加上移动构造和移动赋值)

否则,默认的浅拷贝会让你陷入万劫不复的调试深渊!


✅ 总结

  • 编译器自动生成的operator=浅拷贝,对指针极其危险。

  • 当类中有堆区指针时,必须重载赋值运算符,实现深拷贝

  • 记得:先释放旧资源,再分配新资源,最后返回*this

  • 支持链式赋值的关键:返回引用


如果你觉得这篇推文帮你避开了一个大坑,欢迎点赞、收藏、转发!
也欢迎留言:“你在项目中遇到过浅拷贝导致的 bug 吗?”


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

PyTorch-CUDA-v2.6镜像中使用Hydra管理复杂实验配置

PyTorch-CUDA-v2.6 镜像中使用 Hydra 管理复杂实验配置 在深度学习项目开发中&#xff0c;一个常见的尴尬场景是&#xff1a;你在本地调通了模型&#xff0c;信心满满地把代码交给同事复现&#xff0c;结果对方跑起来却报错——“CUDA 版本不兼容”、“PyTorch 导入失败”、“某…

作者头像 李华
网站建设 2026/4/18 12:08:47

PyTorch-CUDA-v2.6镜像中的cuDNN版本确认方法

PyTorch-CUDA-v2.6镜像中的cuDNN版本确认方法 在深度学习项目中&#xff0c;一个看似微不足道的环境配置问题&#xff0c;往往会导致数小时甚至数天的调试时间。比如&#xff0c;你刚刚从同事那里拿到一个标榜“开箱即用”的 pytorch-cuda:v2.6 镜像&#xff0c;信心满满地启动…

作者头像 李华
网站建设 2026/4/18 5:33:34

PyTorch-CUDA-v2.6镜像支持ONNX导出吗?转换流程详解

PyTorch-CUDA-v2.6 镜像支持 ONNX 导出吗&#xff1f;转换流程详解 在现代 AI 工程实践中&#xff0c;一个常见的挑战是&#xff1a;如何快速、可靠地将训练好的 PyTorch 模型部署到不同硬件平台&#xff1f; 尤其是在使用预构建的容器镜像时&#xff0c;开发者常会问&#xf…

作者头像 李华
网站建设 2026/4/17 10:27:37

PyTorch-CUDA-v2.6镜像中安装SpaCy自然语言处理库注意事项

在 PyTorch-CUDA-v2.6 镜像中安装 SpaCy 的实践要点 在当前 AI 工程实践中&#xff0c;一个常见但容易被低估的挑战是&#xff1a;如何在一个已经为深度学习优化过的容器环境中&#xff0c;顺利引入自然语言处理&#xff08;NLP&#xff09;工具链。比如&#xff0c;在基于 PyT…

作者头像 李华
网站建设 2026/4/21 18:20:01

图解说明典型PCB设计案例:入门级双层板布局技巧

从零开始画一块能用的双层板&#xff1a;一个音频放大器的PCB实战笔记你有没有过这样的经历&#xff1f;原理图画得挺顺&#xff0c;仿真波形也漂亮&#xff0c;结果一打样回来&#xff0c;电路要么不工作&#xff0c;要么噪音大得像收音机杂音。别急——问题很可能不在芯片&am…

作者头像 李华
网站建设 2026/4/18 7:54:55

GitHub Actions自动化测试PyTorch-CUDA-v2.6镜像稳定性方案

GitHub Actions自动化测试PyTorch-CUDA-v2.6镜像稳定性方案 在深度学习项目开发中&#xff0c;一个常见的“噩梦”场景是&#xff1a;某位同事兴奋地宣布模型准确率突破新高&#xff0c;结果你拉下代码、复现环境后却发现——CUDA不可用&#xff0c;PyTorch报错&#xff0c;甚至…

作者头像 李华