深拷贝构造函数不能用memcpy,因其仅复制字节而不调用构造函数或处理资源所有权,导致共享堆内存和double free;正确做法是为每个元素分配新内存并逐个初始化。

深拷贝构造函数为什么不能直接用 memcpy?
因为数组成员如果是指针(比如 int*)、对象(含动态资源)或包含指针的类,memcpy 只复制内存字节,不会调用元素的构造函数或处理资源所有权——结果是两个对象共享同一块堆内存,析构时重复释放,触发 double free 或崩溃。
真正需要的是:为每个元素分配新内存,并逐个初始化(而非复制地址)。
- 原始数组是
int*?得用new int[size]分配,再用循环赋值 - 原始数组是
std::string*?必须对每个std::string调用拷贝构造,不能只复制指针 - 用
std::vector替代裸数组?它默认就是深拷贝,无需手写构造函数
手动实现深拷贝构造函数的三步关键操作
以管理 int* 的类为例,核心是:申请、复制、记录长度。
class IntArray {
int* data_;
size_t size_;
public:
IntArray(const IntArray& other) : size_(other.size_) {
data_ = new int[size_]; // 1. 分配新内存
for (size_t i = 0; i
- 初始化列表里先设
size_,再在函数体中用它分配内存——顺序不能反 - 不能写成
data_ = other.data_,那是浅拷贝 - 如果类有多个指针成员,每个都得单独 new + 循环拷贝
遇到 std::unique_ptr<t></t> 怎么办?
它本身禁止拷贝,所以不能直接用于需要深拷贝的场景;但可以显式实现:用 std::make_unique 分配新数组,再用 std::copy 拷贝内容。
class SafeArray {
std::unique_ptr<int> data_;
size_t size_;
public:
SafeArray(const SafeArray& other) : size_(other.size_) {
data_ = std::make_unique<int>(size_);
std::copy(other.data_.get(), other.data_.get() + size_, data_.get());
}
};</int></int>
-
std::unique_ptr的拷贝构造函数被删除,必须自己写逻辑 -
std::copy是安全的,比手写循环更不易出错 - 如果元素类型是自定义类,确保其拷贝构造函数可访问且正确
容易被忽略的边界和陷阱
深拷贝不是“多写几行代码”就完事,几个细节不处理就会埋雷:
- 源对象
data_为nullptr?分配前要检查,否则new int[0]合法但循环会跳过,而nullptr拷贝过去会导致未定义行为 - 拷贝过程中抛异常(比如
new失败)?当前写法没异常安全机制,应考虑用 RAII 或两阶段分配 - 数组元素类型含虚函数或继承关系?确保拷贝的是实际类型,而不是切片(slicing),必要时用虚拷贝函数
- 如果类还支持移动构造,深拷贝构造函数不能干扰移动语义——两者逻辑必须正交
裸数组的深拷贝本质是资源所有权转移的显式表达,每一步分配和初始化都得对得上析构里的释放逻辑。漏掉一个 []、少一次循环、或错用指针,运行时问题往往延迟暴露。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











