1. 从内存视角理解拷贝行为
在C++中,对象拷贝的核心差异体现在内存管理方式上。假设我们有一个简单的Person类:
cpp复制class Person {
public:
char* name;
int age;
Person(const char* n, int a) {
name = new char[strlen(n) + 1];
strcpy(name, n);
age = a;
}
};
当执行Person p1("Alice", 25); Person p2 = p1;时,浅拷贝直接复制指针值,导致两个对象的name成员指向同一块堆内存。这种行为的危险在于:
- 任一对象修改name内容会影响另一个对象
- 析构时会导致同一内存被释放两次(double free)
- 内存泄漏风险(如果其中一个对象提前释放)
而深拷贝的正确实现应该是:
cpp复制Person(const Person& other) {
name = new char[strlen(other.name) + 1];
strcpy(name, other.name);
age = other.age;
}
这样每个对象都拥有独立的name内存空间,修改互不影响,析构也安全。
关键经验:任何包含指针成员且指针指向动态分配内存的类,都必须实现深拷贝。这是C++资源管理的黄金法则之一。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 默认拷贝构造函数的陷阱
编译器生成的默认拷贝构造函数执行的是逐成员浅拷贝(member-wise copy)。对于基本类型成员这没有问题,但对指针成员就是灾难。看这个典型错误案例:
cpp复制class String {
char* data;
public:
String(const char* str = "") {
data = new char[strlen(str)+1];
strcpy(data, str);
}
~String() { delete[] data; }
// 缺少拷贝构造函数
};
void demo() {
String s1("hello");
String s2 = s1; // 灾难开始
} // 双重释放崩溃
当s2被创建时,默认拷贝构造函数只是简单复制了data指针值。函数结束时:
- s2析构释放data指向的内存
- s1析构再次尝试释放同一块内存 → 程序崩溃
解决方案是实现拷贝构造函数:
cpp复制String(const String& other) {
dat
