C++ 学习(6)——浅复制与深复制
理解 C++ 中的浅复制与深复制:本质、区别与实践
在 C++ 中进行对象赋值或传参时,常常涉及“复制”操作。但复制并非简单的值传递——它背后隐藏着一对关键概念:浅复制(Shallow Copy)与深复制(Deep Copy)。
这两个概念对于管理资源、避免内存泄漏或悬挂指针等问题至关重要。本文将从本质概念、代码示例、内存模型、何时使用等方面全面解读。
一、复制的本质:值的复制 vs 指针的复制
在 C++ 中,默认的复制构造函数和赋值操作符执行的是浅复制,即对每个成员变量进行“逐位复制”。对于普通数据类型这没有问题,但当类中包含指针成员时,就必须谨慎对待。
二、什么是浅复制(Shallow Copy)?
浅复制是默认行为,它简单地复制对象中所有成员的值,包括指针本身的值(即内存地址),而不会复制指针所指向的内容。
🔸 示例:
class Shallow {
public:
int* data;
Shallow(int val) {
data = new int(val);
}
// 使用默认的复制构造函数(浅复制)
~Shallow() {
delete data;
}
};
int main() {
Shallow obj1(10);
Shallow obj2 = obj1; // 浅复制
*obj2.data = 20;
std::cout << *obj1.data << std::endl; // 输出 20
}
🔸 问题:
obj1和obj2的data指向 相同的地址。- 当
obj1和obj2被析构时,同一块内存被释放两次,导致程序崩溃(double free)。
三、什么是深复制(Deep Copy)?
深复制是对对象中所有资源的完全复制。对于指针,深复制会分配新的内存并复制原始数据内容,两个对象拥有独立的数据副本。
✅ 示例:
class Deep {
public:
int* data;
Deep(int val) {
data = new int(val);
}
// 自定义复制构造函数(深复制)
Deep(const Deep& other) {
data = new int(*other.data); // 分配新内存,复制值
}
~Deep() {
delete data;
}
};
int main() {
Deep obj1(10);
Deep obj2 = obj1; // 深复制
*obj2.data = 20;
std::cout << *obj1.data << std::endl; // 输出 10
}
✅ 优点:
- 避免双重释放问题。
- 两个对象互不干扰,内存安全。
四、深复制需要实现哪些函数?
当类中包含指针成员时,必须手动实现如下三大函数(俗称“三五法则”或 Rule of Three):
class MyClass {
private:
int* data;
public:
// 构造函数
MyClass(int val) {
data = new int(val);
}
// 自定义复制构造函数
MyClass(const MyClass& other) {
data = new int(*other.data);
}
// 自定义赋值操作符
MyClass& operator=(const MyClass& other) {
if (this == &other) return *this; // 自赋值检查
delete data;
data = new int(*other.data);
return *this;
}
// 析构函数
~MyClass() {
delete data;
}
};
五、浅复制 vs 深复制:对比表格
| 项目 | 浅复制 | 深复制 |
|---|---|---|
| 拷贝内容 | 指针地址(引用同一资源) | 分配新内存并复制数据 |
| 数据独立性 | 否 | 是 |
| 内存管理风险 | 高(易 double delete) | 低 |
| 系统默认行为 | 是 | 否(需自定义构造/赋值函数) |
| 适用场景 | 资源共享但只读访问 | 独立资源或需要修改数据副本 |
六、何时需要深复制?
你应当在以下场景主动实现深复制:
- 类中包含动态分配的资源(如
new分配的数组、结构体、句柄等)。 - 对象之间需要独立维护资源(比如图像拷贝、缓存数据等)。
- 存在生命周期交叉或所有权不清晰的指针数据。
七、现代 C++ 替代方案(推荐)
从 C++11 开始,推荐使用智能指针(如 std::unique_ptr, std::shared_ptr)管理资源,避免手动复制和释放指针资源:
#include <memory>
class Smart {
std::unique_ptr<int> data;
public:
Smart(int val) : data(std::make_unique<int>(val)) {}
// 自动调用移动构造函数或拷贝构造(视 unique/shared 而定)
};
八、总结
- 浅复制是系统默认行为,快速但可能引发内存问题;
- 深复制通过显式实现复制构造函数与赋值运算符,确保资源独立;
- 理解并区分这两者对于 C++ 中的资源管理至关重要;
- 在现代 C++ 中,使用智能指针更安全可靠,大幅减少错误和代码复杂度。

浙公网安备 33010602011771号