深拷贝需手动管理裸指针资源:拷贝构造必须new并复制内容,赋值运算符须防自赋值和异常,移动操作应置空源指针;否则易double free或崩溃。

深拷贝不是加个 new 就完事——不手动管理资源,std::string 或 std::vector 之外的裸指针必然 double free。
拷贝构造函数里漏掉资源分配,对象一析构就崩
只要类里有 int*、char* 这类裸指针成员,拷贝构造函数必须显式 new 内存并逐字节复制内容。编译器默认生成的浅拷贝只会复制指针值,两个对象指向同一块堆内存。
常见错误现象:double free or corruption (fasttop) 或程序在第二次析构时 SIGABRT。
- 先检查成员是否有动态分配资源(
new/malloc) - 在拷贝构造函数中为每个裸指针成员调用
new,再用std::copy或循环复制数据 - 别忘了同步拷贝长度/容量等元信息(比如
m_size、m_capacity) - 如果用了
std::unique_ptr,它自动深拷贝语义不成立——std::unique_ptr不可拷贝,只能移动
赋值运算符重载没处理自赋值,memcpy 直接越界
operator= 比拷贝构造更危险:它要先释放旧资源,再复制新资源。如果写成 a = a,自赋值下先 delete[] m_data,再用已失效指针去 memcpy,结果未定义。
立即学习“C++免费学习笔记(深入)”;
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
使用场景:容器扩容、函数返回局部对象、std::vector::push_back 触发元素复制时都可能触发赋值。
- 第一行必须加自赋值检查:
if (this == &other) return *this; - 不能直接复用拷贝构造逻辑——得先
delete当前资源,再分配+复制 - 建议采用 copy-and-swap 惯用法:传参用值传递(触发拷贝构造),再
swap成员,靠临时对象析构清理旧资源,天然避免自赋值和异常安全问题 - 若手动管理内存,
new失败抛出std::bad_alloc前,确保对象仍处于有效状态(强异常安全难,至少保证基本异常安全)
move 构造/赋值没禁用或没实现,深拷贝逻辑被悄悄绕过
一旦类定义了拷贝构造或赋值,编译器不会自动生成移动版本。但 STL 容器(如 std::vector)在扩容时优先尝试移动;如果移动不可用,就退回到拷贝——性能暴跌,且可能掩盖资源泄漏。
参数差异:MyClass(const MyClass&) 是拷贝,MyClass(MyClass&&) 是移动;后者应把源对象的指针置为 nullptr,避免析构时二次释放。
- 若类管理资源,显式删除拷贝操作(
= delete)或显式定义移动操作(= default或手写) - 移动构造中,直接交换指针:
std::swap(m_data, other.m_data),再把other.m_size = 0 - 赋值运算符重载后,记得也提供移动赋值:
MyClass& operator=(MyClass&& other) noexcept - 标记
noexcept很关键——STL 移动操作依赖它判断是否可移动优化
真正麻烦的从来不是写几行 new 和 delete,而是所有路径(拷贝、赋值、移动、异常分支)下资源的生命周期是否严格一一对应。一个没置空的 nullptr,一次忘加的自赋值检查,就足够让调试时间翻倍。
















