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

为什么要用深拷贝

为什么要用深拷贝

在C++中,当类包含堆内存指针成员时,编译器默认的浅拷贝会引发内存重复释放、资源被非法篡改等致命问题,

深拷贝是解决该类问题的核心手段。

浅拷贝的问题

C++编译器会自动生成默认拷贝构造函数,其逻辑为成员变量逐值拷贝

该行为对基本数据类型无影响,但对指向堆内存的指针,仅拷贝内存地址,而非指针指向的堆内存内容,最终导致多个对象共享同一块堆内存,引发程序崩溃。

#include<iostream>#include<cstring>usingnamespacestd;classHouse{private:int*area;public:House(inta):area(newint(a)){cout<<"构造函数执行,堆内存地址:"<<(void*)area<<endl;}~House(){if(area!=nullptr){deletearea;area=nullptr;cout<<"析构函数执行,释放堆内存:"<<(void*)area<<endl;}}voidsetArea(inta){*area=a;}voidshowInfo()const{cout<<"面积:"<<*area<<",堆内存地址:"<<(void*)area<<endl;}};intmain(){Househ1(120);House h2=h1;// 触发默认浅拷贝,仅拷贝area的地址// 打印两个对象的信息,验证指针指向同一堆内存h1.showInfo();h2.showInfo();return0;}

通过对象初始化新对象触发默认拷贝构造函数,运行代码会直接崩溃,核心问题为堆内存重复释放

上述代码运行时,h1h2area指针指向同一块堆内存

  • 程序结束时,析构函数会先释放h2的堆内存,再释放h1的堆内存;
  • 对已释放的堆内存再次执行delete,触发C++内存访问错误,程序直接崩溃。
  • 额外问题:修改h1.setArea(150)h2的面积也会被篡改,因为二者共享堆内存资源。

深拷贝

深拷贝的核心逻辑:为新对象重新分配独立的堆内存,再将原对象堆内存的内容拷贝至新内存,使拷贝后的对象与原对象拥有相同属性但独立的资源,彼此的内存操作互不影响。

仅在原有House类中添加自定义拷贝构造函数即可,其余代码不变:

#include<iostream>#include<cstring>usingnamespacestd;classHouse{private:int*area;public:House(inta):area(newint(a)){cout<<"构造函数执行,堆内存地址:"<<(void*)area<<endl;}// 自定义深拷贝构造函数:核心实现House(constHouse&other){// 1. 为新对象分配独立的堆内存this->area=newint;// 2. 将原对象堆内存的内容,拷贝至新堆内存*this->area=*other.area;cout<<"深拷贝构造函数执行,新堆内存地址:"<<(void*)this->area<<endl;}~House(){if(area!=nullptr){deletearea;area=nullptr;cout<<"析构函数执行,释放堆内存:"<<(void*)area<<endl;}}voidsetArea(inta){*area=a;}voidshowInfo()const{cout<<"面积:"<<*area<<",堆内存地址:"<<(void*)area<<endl;}};intmain(){Househ1(120);// 构造h1,分配堆内存House h2=h1;// 触发深拷贝,为h2分配新的堆内存// 打印信息:验证两个对象堆内存地址不同,内容相同cout<<"h1:";h1.showInfo();cout<<"h2:";h2.showInfo();// 修改h1的面积,验证h2不受影响h1.setArea(150);cout<<"修改h1面积后:"<<endl;cout<<"h1:";h1.showInfo();cout<<"h2:";h2.showInfo();return0;// 析构h2和h1,释放各自的堆内存,程序正常结束}

同样的主函数逻辑,深拷贝下两个对象拥有独立堆内存无重复释放问题,且修改一个对象不会影响另一个。

构造函数执行,堆内存地址:0x55f8d2a8eeb0 深拷贝构造函数执行,新堆内存地址:0x55f8d2a8ef00 h1:面积:120,堆内存地址:0x55f8d2a8eeb0 h2:面积:120,堆内存地址:0x55f8d2a8ef00 修改h1面积后: h1:面积:150,堆内存地址:0x55f8d2a8eeb0 h2:面积:120,堆内存地址:0x55f8d2a8ef00 析构函数执行,释放堆内存:0x0 析构函数执行,释放堆内存:0x0

从结果可看出:

  • h1h2的堆内存地址完全不同,实现了资源独立;
  • 修改h1的面积,h2无变化,避免了资源篡改;
  • 析构函数正常释放各自的堆内存,无重复释放问题,程序正常结束。

深拷贝需配合赋值运算符重载

若在代码中使用赋值操作h2 = h1),仅自定义拷贝构造函数仍会触发浅拷贝问题,需同时重载赋值运算符,实现赋值操作的深拷贝。

House类中添加赋值运算符重载函数,核心逻辑与深拷贝构造函数一致:

// 重载赋值运算符,实现赋值操作的深拷贝House&operator=(constHouse&other){// 防止自赋值(h1 = h1)if(this==&other){return*this;}// 释放当前对象已有的堆内存,避免内存泄漏if(this->area!=nullptr){deletethis->area;}// 重新分配堆内存,拷贝内容this->area=newint;*this->area=*other.area;cout<<"赋值运算符深拷贝,新堆内存地址:"<<(void*)this->area<<endl;return*this;}

总结

  1. 浅拷贝:编译器默认实现,仅逐值拷贝成员变量,仅适用于无堆内存指针的简单类;含堆内存指针时,会导致多个对象共享堆内存,引发重复释放内存资源篡改
  2. 深拷贝:通过自定义拷贝构造函数+赋值运算符重载实现,为新对象分配独立的堆内存并拷贝内容,使对象资源完全独立,解决浅拷贝的所有问题。
  3. 使用场景:当自定义类包含堆内存指针、动态数组、容器等需要手动管理的资源时,必须实现深拷贝。
  4. 核心原则:深拷贝的本质是拷贝资源本身,而非资源的地址;浅拷贝则是拷贝资源地址,而非资源本身。
  5. 通俗易懂浅拷贝就是被复制的和复制的是同一片地址;而深拷贝的话是两个不同的地址。
http://www.jsqmd.com/news/436715/

相关文章:

  • 2026年3月端午礼品厂家最新推荐,节日礼盒定制实力供应商 - 品牌鉴赏师
  • 2026年3月苏州本地代理记账机构精选推荐:财务/财税代理记账选择指南,道之然财务打造优质服务标杆 - 海棠依旧大
  • 从AlphaZero原理到多智能体自主软件开发:理想蓝图与现实进路
  • 2026年山东真空泵厂家Top5推荐:不锈钢真空泵、水环真空泵、真空泵出口、真空负压泵站厂家选择专注实干型小厂优选榜单 - 海棠依旧大
  • JavaScript性能优化技术全面解析:从代码分割到内存管理
  • 2026别再熬夜做PPT啦!这些神器轻松搞定 - 品牌测评鉴赏家
  • 快速排序优化
  • 2026年3月北京工业设计公司推荐:产品、外观、结构、设备、仪器、机器人、产品外观设计公司,上品设计解锁创新新路径 - 海棠依旧大
  • 告别PPT制作噩梦!这些神器让你效率狂飙 - 品牌测评鉴赏家
  • 2026年桂林旅游旅公司最新推荐:桂林旅行、阳朔旅游、阳朔旅行、龙胜旅游、桂林自由行、桂林定制游、桂林私家团厂家选择指南 - 海棠依旧大
  • 2026年无锡搬家公司最新推荐:居民搬家、 钢琴搬运、鱼缸搬家、 长途搬家、 大件搬运、 设备搬迁、 仪器搬运、 日式搬家、 空调移机拆装公司选择指南 - 海棠依旧大
  • 52pj2026春节红包解题-安卓中级
  • 2026年3月塑料中空格子板片生产线厂家最新推荐,中空板材智能生产线 - 品牌鉴赏师
  • 2026山东碳化硼厂家优选推荐榜:碳化硼粉/高丰度碳化硼/碳化硼陶瓷/无压碳化硼/热压碳化硼/超细碳化硼/高纯碳化硼/碳化硼球/碳化硼喷嘴,华恩领衔品质突围 - 海棠依旧大
  • 厦门家长必看!小学自然拼读补习班大盘点 - 品牌测评鉴赏家
  • 2026年南京复印机出租优质服务商推荐榜:打印机租赁、复印机租赁、复印机销售、复印机租赁、打印机出租、会展复议出租厂家选择指南 - 海棠依旧大
  • 厦门家长必看!精选口才课机构大揭秘 - 品牌测评鉴赏家
  • 有实力的橡胶木生产厂家推荐 - 品牌推荐(官方)
  • 2026年成都知识产权交易服务平台推荐,精选5大优质电商平台解锁交易新体验 - 睿易优选
  • 2026年山东升降机厂家权威榜单:液压升降机、移动升降机、自行走升降机、升降平台、卸货平台、液压升降平台厂家选择安全高效适配多场景 - 海棠依旧大
  • 2026年山东真空泵厂家推荐榜:2BV真空泵、2BE真空泵、2BV水环式真空泵、2BE水环式真空泵厂家选择以技术实力筑牢工业真空根基 - 海棠依旧大
  • 解放双手!PPT生成工具大盘点,效率UPUP! - 品牌测评鉴赏家
  • 深度神经网络到AI大语言模型:一场被“误认为突然发生”的技巧演进
  • 防御式PHP代码,让代码“拒绝”出错
  • 大数据领域Kafka与实时数据处理的完美结合
  • 彼得林奇的“市场领导者“转型能力评估
  • Git 热修复流程
  • 厦门家长闭眼入!口才机构红榜出炉 - 品牌测评鉴赏家
  • 告别假努力:实测5款文献阅读神器,帮你从入门到高效!
  • 自适应推理算法中神经编程的突破性进展