默认拷贝构造函数执行浅拷贝,仅复制指针地址;深拷贝需手动分配内存、复制内容、更新指针,并同步实现赋值运算符与析构函数,推荐使用std::vector等RAII容器替代裸指针。

拷贝构造函数默认是浅拷贝
当你没写 MyClass(const MyClass& other),编译器自动生成的拷贝构造函数会逐字节复制成员变量。如果类里有指针(比如 int* data),它只复制指针地址,不复制指针指向的内容——两个对象的 data 指向同一块内存。析构时各自 delete 同一块内存,触发 double free 或崩溃。
深拷贝必须手动分配新内存并复制内容
实现深拷贝的关键动作就三步:申请新内存 → 复制原数据 → 更新指针。不能依赖 memcpy 或默认赋值,必须显式控制资源所有权。
- 在拷贝构造函数里用
new分配和原对象等大的内存 - 用循环或
std::copy把原对象的数据逐个拷贝过去 - 记得同步拷贝其他资源:文件句柄、socket、
std::mutex等需单独处理(通常不能拷贝,应禁用或重置)
class Buffer {
public:
Buffer(const Buffer& other) : size_(other.size_) {
data_ = new char[size_];
std::copy(other.data_, other.data_ + size_, data_);
}
~Buffer() { delete[] data_; }
private:
char* data_;
size_t size_;
};只写拷贝构造函数还不够:必须同步实现赋值运算符
否则 a = b 仍走默认浅拷贝,导致悬空指针或内存泄漏。赋值运算符要处理自赋值、释放旧资源、再深拷贝新资源。
- 先检查
if (this == &other) return *this; - 用
delete[] data_清理当前内存 - 再按拷贝构造逻辑分配+复制
- 强烈建议用“拷贝-交换”惯用法(
swap+ 临时对象),自动处理异常安全和自赋值
现代 C++ 更推荐用 RAII 容器替代裸指针
手动管理 new/delete 极易出错。用 std::vector、std::string、std::unique_ptr 后,编译器生成的拷贝构造函数天然就是深拷贝(对 vector 是元素级拷贝,对 unique_ptr 是移动而非拷贝)。
立即学习“C++免费学习笔记(深入)”;
-
std::vector→ 拷贝构造自动深拷贝所有元素data_; -
std::unique_ptr→ 不可拷贝,强制你思考所有权,避免误用data_; - 裸指针只在极少数性能敏感且必须绕过容器开销的场景才保留
深拷贝真正麻烦的从来不是“怎么写”,而是“要不要写”——多数时候,用对容器就能绕过整个问题。但一旦用了裸指针,就必须把拷贝构造、赋值、析构三个函数一起写全,缺一不可。










