目录
一、默认拷贝构造函数的陷阱(浅拷贝)
class MyString {
private:
char* ptr; // 指向动态分配的内存
public:
// 默认拷贝构造函数(按位拷贝)
MyString(const MyString &st) : ptr(st.ptr) {} // 浅拷贝:仅复制指针地址
};
问题分析:
-
浅拷贝本质:直接复制指针值,新旧对象共享同一块内存。
-
致命缺陷:
-
重复释放:析构时多个对象尝试释放同一内存,导致崩溃。
-
悬空指针:一个对象释放内存后,其他对象指针失效。
-
数据篡改:通过任意对象修改内容,影响所有共享对象。
-
二、自定义拷贝构造函数(深拷贝)
class MyString {
private:
char* ptr;
public:
// 构造函数:动态分配内存
MyString(const char* str = nullptr) {
if (str) {
int len = strlen(str);
ptr = new char[len + 1];
strcpy(ptr, str);
} else {
ptr = new char[1];
*ptr = '\0';
}
}
// 深拷贝构造函数
MyString(const MyString& st) {
if (st.ptr) {
int len = strlen(st.ptr);
ptr = new char[len + 1]; // 独立分配新内存
memcpy(ptr, st.ptr, len + 1); // 复制内容而非指针(比strcpy更高效)
} else {
ptr = nullptr; // 处理空指针边界条件
}
}
// 析构函数:安全释放内存
~MyString() {
delete[] ptr; // delete[] 匹配 new[]
ptr = nullptr; // 避免悬空指针
}
};
关键改进:
-
独立内存分配:每个对象持有独立内存块。
-
内容复制:使用
memcpy
或strcpy
确保数据完整性。 -
边界处理:明确处理空指针输入场景。
三、深拷贝与浅拷贝对比
特性 | 浅拷贝 | 深拷贝 |
---|---|---|
内存共享 | 是(多个对象指向同一内存) | 否(每个对象拥有独立内存) |
安全性 | 低(重复释放/悬空指针) | 高(内存隔离) |
适用场景 | 无动态内存管理的简单类型(如int) | 含指针/动态资源的类(如字符串) |
实现复杂度 | 自动生成(无需编码) | 需显式实现拷贝构造/赋值运算符 |
四、注意事项
-
三人行
若自定义拷贝构造函数、拷贝赋值运算符或析构函数中的一个,必须显式实现三者。 -
优先使用
std::string
:
避免手动管理内存,直接利用标准库的深拷贝能力。 -
深拷贝工具优化:
-
使用
memcpy
替代strcpy
提升大内存块复制效率。 -
添加
nullptr
检查防止未定义行为。
-