浅拷贝可能带来的问题
- 内存重复释放:当类中包含动态分配的内存(如通过
new
分配的指针成员),浅拷贝只是简单地复制指针的值,而不是复制指针所指向的内存。这就导致两个对象的指针指向同一块内存,当其中一个对象析构释放内存时,另一个对象的指针就变成了野指针,再次访问或析构时会导致程序崩溃。
- 数据修改相互影响:由于两个对象的指针指向同一块内存,对其中一个对象的数据修改会影响到另一个对象,这可能导致逻辑错误。
自定义拷贝构造函数实现深拷贝示例
#include <iostream>
#include <cstring>
class MyString {
private:
char* str;
int length;
public:
// 构造函数
MyString(const char* s = nullptr) {
if (s == nullptr) {
length = 0;
str = new char[1];
str[0] = '\0';
}
else {
length = strlen(s);
str = new char[length + 1];
strcpy(str, s);
}
}
// 析构函数
~MyString() {
delete[] str;
}
// 自定义拷贝构造函数(深拷贝)
MyString(const MyString& other) {
length = other.length;
str = new char[length + 1];
strcpy(str, other.str);
}
// 重载赋值运算符(深拷贝)
MyString& operator=(const MyString& other) {
if (this == &other) {
return *this;
}
delete[] str;
length = other.length;
str = new char[length + 1];
strcpy(str, other.str);
return *this;
}
void print() const {
std::cout << str << std::endl;
}
};
int main() {
MyString s1("Hello");
MyString s2(s1); // 使用自定义拷贝构造函数
s1.print();
s2.print();
s2 = MyString("World"); // 使用重载的赋值运算符
s1.print();
s2.print();
return 0;
}
深拷贝必要的情况
- 类中包含动态分配的资源:如上述
MyString
类中动态分配了字符数组,如果不进行深拷贝,多个对象共享同一块动态内存会带来问题。
- 对象内部状态需要独立管理:当对象的某个成员代表一种需要独立拥有的资源(如文件句柄、网络连接等),为了每个对象对该资源的操作不相互干扰,需要深拷贝来确保每个对象有自己独立的资源副本。