当前位置: 首页 > news >正文

一文深入了解深拷贝 和 浅拷贝

一文深入了解深拷贝 和 浅拷贝


文章目录

  • 一文深入了解深拷贝 和 浅拷贝
    • 一、核心概念
      • 1. 浅拷贝 (Shallow Copy)
      • 2. 深拷贝 (Deep Copy)
    • 二、直观的比喻
    • 三、代码示例(以C++为例)
    • 四、深拷贝的实现方式
    • 五、C++的处理方式
      • C++
    • 六、总结与选择建议
  • 总结

这是一个非常核心且容易混淆的概念,尤其在C++、Java、Python等语言中手动管理对象或数据时。我来为你详细解释深拷贝和浅拷贝,并说明它们的区别、应用场景以及可能带来的问题。

一、核心概念

1. 浅拷贝 (Shallow Copy)

定义:复制对象时,只复制对象本身和其包含的基本数据类型的值,但对于对象中的指针或引用类型的成员,只复制其地址(引用),而不复制指针所指向的实际数据。

结果:原始对象和拷贝对象会共享同一份内部数据(指针指向同一块内存地址)。

2. 深拷贝 (Deep Copy)

定义:复制对象时,不仅复制对象本身,还会为对象中的指针或引用类型的成员分配新的内存,并将原指针所指向的数据完整地复制过来。

结果:原始对象和拷贝对象各自拥有独立的一份数据,互不影响。


二、直观的比喻

把对象想象成一个名片盒

  • 名片盒A里有一张名片,名片上写着一个仓库的地址(这个仓库就是实际的数据)。
  • 浅拷贝:你做了一个新的名片盒B,里面放了一张新的名片,但名片上写的还是同一个仓库的地址。A和B指着同一个仓库。
  • 深拷贝:你做了一个新的名片盒B,然后新建了一个一模一样的仓库,并把原仓库里的东西都搬过去。B里放的新名片,写的是新仓库的地址。A和B各自指着自己的仓库。

三、代码示例(以C++为例)

这是最能体现区别的场景:

#include<iostream>#include<cstring>// for memcpy, strcpyusingnamespacestd;// 一个简单的字符串类,用于演示classMyString{public:char*data;// 指向堆内存的指针// 构造函数MyString(constchar*str){if(str){data=newchar[strlen(str)+1];strcpy(data,str);}else{data=nullptr;}}// 1. 默认的拷贝构造函数 (执行浅拷贝)MyString(constMyString&other){// ⚠️ 这是浅拷贝:直接复制指针值data=other.data;cout<<"浅拷贝执行: 两个对象指向同一内存 "<<(void*)data<<endl;}// 2. 如果实现了深拷贝的拷贝构造函数 (为了对比,注释掉,但展示写法)/* MyString(const MyString& other) { if (other.data) { data = new char[strlen(other.data) + 1]; // 分配新内存 strcpy(data, other.data); // 复制内容 cout << "深拷贝执行: 新内存地址 " << (void*)data << endl; } else { data = nullptr; } } */// 析构函数~MyString(){delete[]data;// 释放内存cout<<"析构函数释放内存 "<<(void*)data<<endl;}};intmain(){MyStringstr1("Hello");MyString str2=str1;// 调用拷贝构造函数,这里是浅拷贝// 输出两个对象中 data 指针的地址cout<<"str1.data 地址: "<<(void*)str1.data<<endl;cout<<"str2.data 地址: "<<(void*)str2.data<<endl;// 程序结束时,str1 和 str2 的析构函数会被调用// 问题来了:它们会尝试释放同一个内存地址两次!// 这会导致程序崩溃 (double free error)return0;}

运行结果与问题

  1. 输出显示str1.datastr2.data指向完全相同的地址
  2. 程序结束时,str2的析构函数先执行,释放了那块内存。
  3. 随后str1的析构函数执行,尝试再次释放已经被释放的内存,程序崩溃。

这就是浅拷贝的经典问题:双重释放 (Double Free) 或野指针访问。


四、深拷贝的实现方式

为了解决上述问题,我们需要提供自定义的拷贝构造函数赋值运算符,执行深拷贝:

classMyString{public:char*data;MyString(constchar*str){/* ... 同前 ... */}// 深拷贝构造函数MyString(constMyString&other){if(other.data){data=newchar[strlen(other.data)+1];strcpy(data,other.data);cout<<"深拷贝: 创建新内存 "<<(void*)data<<endl;}else{data=nullptr;}}// 深拷贝赋值运算符 (重要,也需实现)MyString&operator=(constMyString&other){if(this==&other)return*this;// 自赋值检查delete[]data;// 释放原有资源if(other.data){data=newchar[strlen(other.data)+1];strcpy(data,other.data);}else{data=nullptr;}cout<<"深拷贝赋值: "<<(void*)data<<endl;return*this;}~MyString(){delete[]data;cout<<"析构释放 "<<(void*)data<<endl;}};

此时,str1str2拥有各自独立的内存,析构时互不干扰。


五、C++的处理方式

C++

  • 默认行为:类未定义拷贝构造函数时,编译器提供的是浅拷贝(逐位复制)。
  • 风险:当类管理堆内存(如new出来的资源)时,浅拷贝会导致重复释放、内存泄漏等问题。
  • 规则:如果一个类需要析构函数来释放资源,它几乎一定需要自定义的拷贝构造函数和赋值运算符(即“三/五法则”)。

六、总结与选择建议

特性浅拷贝深拷贝
资源管理共享资源,节约内存独立资源,内存占用大
性能快(只复制指针)慢(需要分配内存和复制数据)
复杂度简单,但容易出错相对复杂,需正确处理资源
修改影响修改拷贝会影响原对象修改拷贝不影响原对象
应用场景小对象、只读共享、不涉及资源管理的简单类对象包含动态分配的资源,且需要独立修改和生命周期管理

选择指南

  1. 如果类不管理任何资源(如只包含整数、浮点数、字符数组char[]而非指针),浅拷贝就足够了。
  2. 如果类管理资源(如new出来的内存、文件句柄、网络连接),必须提供深拷贝(或通过引用计数等方式实现写时拷贝,或直接禁止拷贝,如C++11的unique_ptr)。

理解深拷贝和浅拷贝,是写出健壮、无内存泄漏代码的基础。希望这个解释对你有帮助!

总结

这篇文章是作者搜集大量面经和资料这里出来的。感谢你的支持
作者wkm是一名中国矿业大学(北京) 大一的新生,希望得到你的关注
如果可以的话,记得一键三联!

http://www.jsqmd.com/news/436411/

相关文章:

  • 2026年知名的反弹缓冲隐藏轨 工厂推荐:三节缓冲隐藏轨/抽屉缓冲隐藏轨/定制缓冲隐藏轨实力厂家如何选 - 行业平台推荐
  • MySQL范围查询的“截断”效应的庖丁解牛
  • 【人工智能】一文看懂SecondMe协议(SMP):你的AI数字分身“代言人”
  • 2026年比较好的白刚玉砂 品牌推荐:白刚玉磨料/白刚玉微粉/白刚玉颗粒正规生产厂家推荐 - 行业平台推荐
  • CSS 规则的庖丁解牛
  • phpstorm 设置 vmoptions后生成的在什么具体位置
  • HRP体系与独立成本核算管理系统应用价值分析 - 业财科技
  • 阶跃星辰深度开源,Agent 模型潜力几何?
  • 微服务开发面试题标准答案+速记要点
  • MyBatis-Plus 批量操作 SQL 日志不打印问题解决方案
  • 2026年口碑好的水环真空机组 厂家推荐:长吊引水真空机组值得信赖的生产厂家 - 行业平台推荐
  • 多模态大模型对齐实战教程(非常硬核),数据有限也能搞定,收藏这一篇就够了!
  • 2026年热门的EVA TAIC交联剂 品牌推荐:粉末TAIC交联剂/50粉末TAIC交联剂品牌厂家哪家靠谱 - 行业平台推荐
  • Node 快捷方式路径怎么获取
  • 用OpenClaw组建AI团队:一人顶一个部门的实战玩法
  • 重新安装指定 Node 版本、并切换了 Node 版本、但这里运行>npm -v 还是报错:‘npm‘ 不是内部或外部命令,也不是可运行的程序或批处理文件。
  • CodeGenius Memory系统构建教程(非常详细),代码生成上下文控制从入门到精通,收藏这一篇就够了!
  • 【开题答辩全过程】以 衡水微法院小程序的设计与实现为例,包含答辩的问题和答案
  • 【机乎】Clawdbot之后,中文AI社交平台开启“祛魅”时刻
  • OpenClaw+RAG+Agent实战:打造能自动干活的数字员工
  • 2026 公认好用的 AI 论文软件,导师看了都夸专业
  • 阿里千问核心人员离职,AI战略何去何从?
  • 2026年热门的虾仁 工厂推荐:高邮大虾仁口碑好的厂家推荐 - 行业平台推荐
  • 【开题答辩全过程】以 高校学生社团管理系统为例,包含答辩的问题和答案
  • 智能体工程模式:编码新路径
  • 2026年评价高的悬链通过式抛丸机 厂家推荐:网带通过式抛丸机供应商怎么选 - 行业平台推荐
  • 从0到1打造专业职配助手:基于openJiuwen记忆库新特性的AI职业规划实战
  • 谷歌为 Pixel 推全新桌面模式
  • DSP、STM32、FPGA、ZYNQ U盘软件升级功能与软件开发源代码
  • 2026农业AI研讨会:破局与发展