在C++中,当类包含动态分配的资源时,默认的拷贝构造函数只能实现浅拷贝,也就是仅复制指针的值而不复制指针指向的实际内容,这会导致多个对象共享同一块内存,在对象析构时引发重复释放的问题。要实现深拷贝,就需要自定义拷贝构造函数,手动为新对象分配独立的内存并复制原对象的内容。

浅拷贝与深拷贝的差异
浅拷贝的核心是复制对象的成员变量值,对于指针类型的成员,只会复制指针本身,不会复制指针指向的堆内存。而深拷贝会为新对象的指针成员重新分配内存,并将原对象指针指向的内容完整复制到新分配的内存中,两个对象的指针成员指向不同的内存空间,互不影响。
我们可以通过一个简单的示例来看浅拷贝的问题:
#include <iostream>
#include <cstring>
class ShallowCopyDemo {
public:
char* data;
// 默认构造函数,分配内存并赋值
ShallowCopyDemo(const char* str) {
data = new char[strlen(str) + 1];
strcpy(data, str);
}
// 没有自定义拷贝构造函数,使用编译器默认生成的
// 析构函数释放内存
~ShallowCopyDemo() {
delete[] data;
}
};
int main() {
ShallowCopyDemo obj1("hello");
// 这里调用默认拷贝构造函数,执行浅拷贝,obj2.data和obj1.data指向同一块内存
ShallowCopyDemo obj2 = obj1;
std::cout << "obj1 data: " << obj1.data << std::endl;
std::cout << "obj2 data: " << obj2.data << std::endl;
// 程序结束时,obj1和obj2的析构函数都会被调用,同一块内存会被释放两次,导致程序崩溃
return 0;
}
自定义拷贝构造函数实现深拷贝
拷贝构造函数的函数名和类名相同,参数通常是本类对象的常引用,这样可以避免拷贝过程中再次调用拷贝构造函数导致递归,同时也能保证原对象不会被修改。在拷贝构造函数中,我们需要为动态成员重新分配内存,再复制内容。
标准的深拷贝拷贝构造函数写法如下:
#include <iostream>
#include <cstring>
class DeepCopyDemo {
public:
char* data;
// 构造函数,分配内存并初始化
DeepCopyDemo(const char* str) {
if (str != nullptr) {
data = new char[strlen(str) + 1];
strcpy(data, str);
} else {
data = new char[1];
*data = ' ';
}
}
// 自定义拷贝构造函数,实现深拷贝
DeepCopyDemo(const DeepCopyDemo& other) {
// 先为新对象的data分配和原对象相同大小的内存
data = new char[strlen(other.data) + 1];
// 复制原对象data指向的内容到新分配的内存
strcpy(data, other.data);
}
// 析构函数释放动态分配的内存
~DeepCopyDemo() {
delete[] data;
}
// 打印data内容的方法
void printData() {
std::cout << "data: " << data << std::endl;
}
};
int main() {
DeepCopyDemo obj1("deep copy test");
// 调用自定义的拷贝构造函数,执行深拷贝
DeepCopyDemo obj2 = obj1;
obj1.printData();
obj2.printData();
// 修改obj2的data,验证两个对象的内存独立
strcpy(obj2.data, "modified content");
std::cout << "after modify obj2:" << std::endl;
obj1.printData();
obj2.printData();
return 0;
}
拷贝构造函数的注意事项
- 拷贝构造函数的参数必须是
const 类名&类型,不能使用值传递,否则会引发无限递归调用。 - 如果类中包含动态分配的资源,除了自定义拷贝构造函数实现深拷贝,通常还需要自定义赋值运算符重载,避免赋值操作时的浅拷贝问题。
- 拷贝构造函数中需要先判断原对象的成员是否有效,避免对空指针进行操作。
- 如果类没有动态成员,使用编译器默认生成的拷贝构造函数即可,不需要手动实现深拷贝。
总结
实现C++深拷贝的核心是自定义拷贝构造函数,在函数中为动态成员重新分配独立的内存,并复制原对象的内容。正确的拷贝构造函数写法需要遵循参数使用常引用的规则,同时配合析构函数正确管理动态资源。掌握深拷贝的实现方式,能够有效避免内存泄漏、重复释放等常见的C++开发问题。