全面理解-深拷贝与浅拷贝
创作时间:
作者:
@小白创作中心
全面理解-深拷贝与浅拷贝
引用
CSDN
1.
https://blog.csdn.net/HL_LOVE_C/article/details/145699198
在C++开发中,深拷贝和浅拷贝是两个非常重要的概念,它们直接影响着程序的内存管理和运行安全。本文将通过对比分析,帮助读者全面理解深拷贝与浅拷贝的区别、应用场景以及正确的实现方法。
在 C++ 中,深拷贝(Deep Copy) 和 浅拷贝(Shallow Copy) 是两种完全不同的对象拷贝策略,主要区别在于对指针和动态分配资源的处理方式。正确理解二者的区别是避免内存泄漏、悬空指针和程序崩溃的关键。
一、核心区别
特性 | 浅拷贝(Shallow Copy) | 深拷贝(Deep Copy) |
---|---|---|
拷贝内容 | 仅复制指针值(地址),不复制指针指向的内存数据 | 复制指针指向的实际数据,并为新对象分配独立内存 |
内存所有权 | 多个对象共享同一块内存 | 每个对象拥有独立内存 |
资源管理风险 | 容易导致双重释放(double free)或悬空指针 | 内存隔离,安全可靠 |
默认行为 | C++ 默认的拷贝构造函数和赋值运算符是浅拷贝 | 需手动实现 |
适用场景 | 对象不含动态资源或明确需要共享数据 | 对象管理动态分配的资源(如数组、文件句柄等) |
二、示例解析
1. 浅拷贝的陷阱
class ShallowArray {
public:
int* data;
size_t size;
ShallowArray(size_t n) : size(n), data(new int[n]) {}
~ShallowArray() { delete[] data; }
};
int main() {
ShallowArray arr1(5);
ShallowArray arr2 = arr1; // 默认浅拷贝(复制指针)
// 析构时 arr1 和 arr2 的 data 指向同一内存,导致双重释放!
}
2. 深拷贝的实现
class DeepArray {
public:
int* data;
size_t size;
DeepArray(size_t n) : size(n), data(new int[n]) {}
// 深拷贝构造函数
DeepArray(const DeepArray& other) : size(other.size), data(new int[other.size]) {
std::copy(other.data, other.data + size, data);
}
// 深拷贝赋值运算符
DeepArray& operator=(const DeepArray& other) {
if (this != &other) {
delete[] data;
size = other.size;
data = new int[size];
std::copy(other.data, other.data + size, data);
}
return *this;
}
~DeepArray() { delete[] data; }
};
int main() {
DeepArray arr1(5);
DeepArray arr2 = arr1; // 深拷贝,独立内存
// 安全析构
}
三、深拷贝的必要性
当对象包含以下资源时 必须使用深拷贝:
- 动态分配的内存(new/malloc申请)
- 文件句柄(需独立打开/关闭)
- 网络连接(需独立管理)
- 线程锁(避免多个对象共享同一锁)
四、如何正确实现深拷贝
1. 拷贝构造函数
// 深拷贝构造函数
ClassName(const ClassName& other) {
// 分配新资源
resource = new ResourceType(*other.resource);
// 或拷贝数据
std::memcpy(data, other.data, size);
}
2. 赋值运算符
ClassName& operator=(const ClassName& other) {
if (this != &other) { // 处理自我赋值
// 释放旧资源
delete resource;
// 分配新资源并拷贝数据
resource = new ResourceType(*other.resource);
}
return *this;
}
五、浅拷贝的合理使用场景
以下情况 浅拷贝是安全的:
- 对象仅包含基本数据类型(int、double等)
- 对象包含指针但 不拥有所有权(如观察者指针)
- 明确需要共享数据(需配合引用计数或智能指针)
六、现代 C++ 的替代方案
1. 使用智能指针
- std::unique_ptr:禁止拷贝,强制移动语义(隐式深拷贝替代)
- std::shared_ptr:共享所有权,引用计数自动管理资源
class SafeArray {
std::unique_ptr<int[]> data; // 自动管理内存
size_t size;
public:
SafeArray(size_t n) : size(n), data(std::make_unique<int[]>(n)) {}
// 默认禁用拷贝(需深拷贝时手动实现)
};
2. 使用容器类
- std::vector、std::string等标准容器已实现深拷贝
std::vector<int> v1 = {1, 2, 3};
std::vector<int> v2 = v1; // 自动深拷贝
七、总结
操作 | 浅拷贝 | 深拷贝 |
---|---|---|
资源所有权 | 共享资源 | 独占资源 |
内存开销 | 小(仅复制指针) | 大(复制所有数据) |
安全性 | 低(需额外管理共享资源) | 高(资源隔离) |
实现复杂度 | 无需额外实现(默认行为) | 需手动实现拷贝构造函数和赋值运算符 |
核心原则:
- 若对象管理资源(如动态内存),必须实现深拷贝。
- 优先使用智能指针和标准容器,减少手动内存管理。
热门推荐
坤泰胶囊为何被禁了?真相在这里
坤泰胶囊由哪些成分组成
家庭收藏白酒指南:如何长期存放白酒?
如何用小音响组装成5.1声道音箱?视频功能如何实现?
白酒失意春节档:“蛇茅”遇冷,第八代五粮液价格下降
PR软件需要什么配置的笔记本
杭州房产置换与购房建议解析
室內植物指南:新手必學3招|佈置寫意工作空間
经济条件对结婚的影响:一个现代社会中的现实问题
睡姿竟与前世因缘有关,药师佛开示:这个姿势最能改变命运
吉他单音与和弦结合弹奏指南
野钓草鱼方法汇总:5大钓法通杀湖库,爽钓春夏秋
小城银发族的理财“觉醒”
皮肤肿瘤的症状与治疗方法
超三分之二的患者错用吸入装置!他们犯的都是哪些常见错误?
得了糖尿病要如何饮食?有这5个饮食小建议!
湿疹是由于潮湿导致的?答案可能跟你想的不一样
AI大模型应用入门实战与进阶:构建你的第一个大模型:实战指南
脾胃虚寒湿气重怎么调理,脾胃虚寒湿气重,这样调理让你事半功倍
学日语有前途吗?解析日语学习的职业与发展前景
拖欠工资怎么投诉?拖欠工资投诉有用吗?
男生不结婚的罪名:是社会压力还是个人选择?
如何理解钴期货的价格波动?钴期货对新能源行业有何意义?
“勿忘国耻,圆梦中华”学术研讨会在南京举行
DRG分组2.0来了,与临床实际结合,眼学科手术做了哪些调整?
区块链共识机制深度揭秘:从PoW到PoS,谁能主宰未来?
Excel表格制作指南:如何让表格既美观又实用
拔牙后预防感染:奥硝唑等五种常用药物详解
九型人格第 9 类人格 - 和平缔造者 - 适应性维和者
如何报销普通门诊费用?这种报销有什么规定和流程?