深拷贝必须手动分配新内存并同步拷贝长度字段,否则会导致double free、use-after-free等崩溃;赋值运算符和析构函数也需正确实现,推荐用std::vector替代裸指针。

拷贝构造函数里必须手动分配新内存
默认拷贝构造只做浅拷贝,new出来的指针成员会被直接复制,两个对象指向同一块堆内存。析构时重复 delete 就会崩溃。所以必须在拷贝构造里用 new 重新申请内存,并逐个拷贝元素。
常见错误现象:double free or corruption、程序随机崩溃、访问已释放内存(use-after-free)。
- 先检查源对象指针是否为
nullptr,避免对空指针取*size - 用
new T[src.size]分配和源对象等长的数组,别漏掉[] - 用循环或
std::copy拷贝元素,不能直接写data = src.data - 记得同步拷贝长度字段(比如
size或capacity),否则后续操作越界
赋值运算符也得同步处理,否则出问题
只写拷贝构造不写 operator= 是常见疏忽。对象被赋值时不会调用拷贝构造,而是调用赋值运算符——如果没重载,编译器生成的默认版本仍是浅拷贝。
实现要点:
- 自赋值检查:先判断
this == &rhs,防止自己给自己赋值后把原数据删了 - 先
delete[] data释放旧内存(注意加[]),再new新内存 - 拷贝逻辑和拷贝构造一致,但多了释放+分配两步
- 建议用“拷贝-交换”惯用法(
swap实现),更异常安全
推荐用 std::vector 替代裸动态数组
手写深拷贝容易漏掉边界、异常、自赋值等问题。std::vector 内部已正确实现深拷贝语义,且支持移动语义、容量管理、迭代器等。
替换方式很简单:
- 把
T* data和size_t size换成std::vector<t> data</t> - 去掉自定义拷贝构造、赋值、析构——编译器生成的就足够了
- 访问元素改用
data[i]或data.at(i),长度用data.size() - 如果必须用裸指针(如对接 C API),至少封装进 RAII 类,别裸露在类公有接口
析构函数里 delete[] 别写成 delete
这是高频低级错误。用 new[] 分配的必须用 delete[] 释放,否则行为未定义,可能只析构第一个元素,或触发内存检查失败(如 ASan 报 heap-use-after-free)。
检查点:
- 所有
new[]都要配对delete[],包括拷贝构造里 new 出来的那块 - 析构函数里先判空再
delete[],避免对nullptr调用(虽标准允许,但易掩盖逻辑缺陷) - 如果类里有多个动态数组成员,每个都要独立
delete[],顺序无关,但别漏
深拷贝的核心不是“多写几行”,而是确保每块 new[] 都有唯一归属、明确生命周期。最容易被忽略的是:赋值运算符没写、析构里用了错的 delete 形式、以及忘记同步拷贝长度字段——这三个点一出,运行时崩得毫无征兆。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











