必须手写deepcopy构造函数当类含独占管理堆内存的指针成员时,否则默认浅拷贝会导致double free或数据污染;需分配新内存、复制内容、更新指针,并遵循三/五法则。

什么时候必须手写 DeepCopy 构造函数?
当类里含有指针成员(尤其是指向堆内存的 int<em></em>、char、std::string* 等),且该指针所指内存由当前对象独占管理时,编译器生成的默认拷贝构造函数只会复制指针值(浅拷贝),导致两个对象指向同一块内存——析构时重复 delete,或一个对象修改影响另一个。
常见错误现象包括:
- 程序运行中触发
double free or corruption -
Segmentation fault出现在第二次析构后 - 字符串内容莫名被覆盖(比如
char*指向同一缓冲区)
不是所有含指针的类都需要深拷贝:若指针仅作观察用途(如传入的只读 const char*),或由外部统一管理生命周期,则不应深拷贝。
DeepCopy 构造函数怎么写才安全?
核心动作就三步:分配新内存 → 复制原数据 → 更新指针。但必须和析构函数、赋值运算符保持行为一致(即遵循“三法则”或 C++11 后的“五法则”)。
以一个管理动态字符数组的类为例:
class StringWrapper {
char* data_;
size_t len_;
public:
StringWrapper(const char* s) : len_(s ? strlen(s) : 0) {
data_ = new char[len_ + 1];
if (s) strcpy(data_, s);
else data_[0] = '\0';
}
<pre class="brush:php;toolbar:false;">// 深拷贝构造函数
StringWrapper(const StringWrapper& other)
: len_(other.len_) {
data_ = new char[len_ + 1]; // 分配新空间
strcpy(data_, other.data_); // 复制内容,不是指针值
}
~StringWrapper() { delete[] data_; }};
关键点:
- 初始化列表中不初始化
data_,避免在new失败时留下未定义指针 -
new char[len_ + 1]必须和原始分配方式一致(new[]对应delete[]) - 不要写成
data<em> = other.data</em>—— 这是浅拷贝,直接踩坑
为什么 std::string 成员不需要手动深拷贝?
因为 std::string 自身已实现深拷贝语义。它的拷贝构造函数会申请新缓冲区并复制字符,你只需让编译器默认处理即可:
class SafeWrapper {
std::string content_; // ✅ 自动深拷贝
int* ptr_; // ❌ 仍需手动处理
public:
SafeWrapper(const SafeWrapper& other)
: content_(other.content_), // 编译器调用 std::string 的拷贝构造
ptr_(new int(*other.ptr_)) // 你负责这个
{}
};
注意:如果误把 std::string 声明为 std::string*,那它又退化为裸指针,必须手动深拷贝(包括 new string、copy 构造、更新指针),这种情况极少合理,应优先改用值语义。
容易被忽略的边界与陷阱
-
nullptr 检查不能少:若原指针为 nullptr,new 后仍要确保新指针也为空或指向有效空字符串,否则 strcpy 或 memcpy 会崩溃
- 异常安全:若深拷贝过程中抛异常(如
new 失败),已分配的资源必须清理;推荐使用 RAII 封装(如 std::unique_ptr)替代裸指针,从根本上规避手动管理
- 继承场景下,基类若含裸指针且未声明虚析构,派生类深拷贝后可能切片或析构不全
- 移动构造函数存在时,深拷贝构造函数逻辑不能和移动混淆:拷贝必须保证源对象不变,移动可掏空源对象
nullptr 检查不能少:若原指针为 nullptr,new 后仍要确保新指针也为空或指向有效空字符串,否则 strcpy 或 memcpy 会崩溃new 失败),已分配的资源必须清理;推荐使用 RAII 封装(如 std::unique_ptr)替代裸指针,从根本上规避手动管理深拷贝真正麻烦的从来不是“怎么写”,而是“要不要写”——多数现代 C++ 代码应尽量用 std::vector、std::string、std::unique_ptr 等自带深拷贝/移动语义的类型,把裸指针深拷贝留给极少数需要精细控制内存布局或对接 C API 的场景。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











