C++语法|对象的浅拷贝和深拷贝

背景:
我们手写一个顺序栈,展开接下来的实验:
⭐️ this指针指向的是类在内存中的起始位置

class SeqStack {
public:SqeStack(int size = 10) {cout << this << "SeqStack()" << endl;pstack_ = new int[size_];top_ = -1;size_ = size;	}~SeqStack() {cout << this << " ~SeqStack()" << endl;delete[] pstack_;pstack_ = nullptr;}void push(int val) {if (full()) resize();pstack_[++top_] = val;}void pop() {if (empty()) return;--top_;}int top() { return pstack_[top_]; }bool empty() { return top_ == -1; }bool full() { return top_ == size_ - 1; }
private:int *pstack_; //动态开辟数组,存储顺序栈的元素int top_; //指向栈顶元素的位置int size_; //数组扩容的总大小void resize () {int *ptem = new int[size_ * 2];for (int i = 0; i < size_; i++) {ptmp[i] = pstack_[i];}delete[] pstack_;pstack_ = ptmp;size_ *= 2}
};

文章目录

  • 浅拷贝
  • 自定义拷贝构造
  • 为什么不用memcpy
  • 赋值操作引起的浅拷贝问题
  • 重载赋值运算符

浅拷贝

int main () {SeqStack s1(10);SeqStack s2 = s1;  //#1//SeqStack s3 = s1; #2 1和2都是调用拷贝构造//SeqStack s4; s4 = s1 #这个才是调用operator=return 0;
}

程序会直接崩溃,终端提示我们两次释放相同的内存空间,造成内存泄漏。
这是由于代码SeqStack s2 = s1;明显是调用了默认的拷贝构造函数,默认的拷贝构造其实是一个浅拷贝。
可以看如下图:
在这里插入图片描述
所以说在析构的时候,先析构s2,导致我们new int[10]这块内存就已经没有了,s1中的pstack_成为了一个野指针,我们在析构一个已经释放了的内存。

总结:
对象默认的拷贝构造事做内存的数据拷贝。
关键是对象如果占用了外部资源,那么浅拷贝就出现问题了。
如果之后我们发现一个对象有一个指针,并且这个指针还指向一个外部的(堆)上的内存,所以我们一定要警防浅拷贝。

此时我们一定不能依靠编译器为我们自动生成的拷贝构造

自定义拷贝构造

SeqStack(const SeqStack &src) {//以下就是默认的浅拷贝操作//pstack_ = src.pstack_;//top_ = src.top_;//size_ = src.size_;pstack_ = new int[srtc.size_];for (int i = 0; i <= src.top_; ++i) {pstack_ = src.pstack_;}top_ = src.top_;size_ = src.size_;
}

在这里我们就对指针类型做了一个深拷贝。

为什么不用memcpy

我们在进行数据拷贝的时候,都是用的for循环,而不用memcpy,这是为什么呢?

在这里插入图片描述
如图所示,我们需要把小内存的数据全部放到大内存上来实现扩容,或者数据的迁移。

因为我们在进行数据拷贝的时候,假如我们要把这块内存上的数据拷贝到那块内存上,如果这块内存上的数据仅仅是里面放int型,但是每一个整型都不占用该整型之外的资源(堆上的资源),就是说这块内存本身就只是放了一块值而已。

那使用内存的memcpy拷贝到那块大内存中,那是没有任何问题的。

那我们假设一下,这个数组里面放的不是整型,而是对象,而且每一个对象里面都有指针,而且还指向了外部的资源,也就是说这个数组里面存的对象的浅拷贝是有问题的。

比如说我们的ptmp[i]里面放的不是整型而是对象,那么我用memcpoy的话就只是把对象本身的内存拷贝了一份,这做的都是浅拷贝的操作

浅拷贝的问题就是,让我们拷贝完的对象里面由于指针跟我们原来对象内存里面的指针指向的都是同一块资源,等我们拷贝完之后,删除小内存中的对象,会自动调用析构函数,析构函数会释放对象资源,那不就直接把我们打指针对象指向的那块堆内存也释放掉了。导致我们拷贝的那些对象的指针都成为了野指针。
在这里插入图片描述
所以说面向对象编程里面,数据的拷贝必须得用for循环来防止内存泄漏的问题

赋值操作引起的浅拷贝问题

int main () {SeqStack s1(10);SeqStack s2 = s1;  //#1//SeqStack s3 = s1; #2 1和2都是调用拷贝构造//SeqStack s4; s4 = s3; //赋值操作=》做直接的潜拷贝return 0;}
}

同理,如果我们不在类里面不重载赋值运算符,编译器会为我们调用默认的赋值操作。

我们仍然会在第二次析构的时候出现问题。

所以我们需要重载赋值运算符operator=

重载赋值运算符

void operator= (const SeqStack &src) {pstack_ = new int[srtc.size_];for (int i = 0; i <= src.top_; ++i) {pstack_ = src.pstack_;}top_ = src.top_;size_ = src.size_;
}

至此,完美解决。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/704939.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Blender 导入资源包的例子

先到清华源下载资源包&#xff1a; Index of /blender/ | 清华大学开源软件镜像站 | Tsinghua Open Source Mirror 具体地址&#xff1a;https://mirrors.tuna.tsinghua.edu.cn/blender/demo/asset-bundles/human-base-meshes/human-base-meshes-bundle-v1.1.0.zip 解压/hum…

2024自学网络安全的三个必经阶段(含路线图)_网络安全自学路线

一、为什么选择网络安全&#xff1f; 这几年随着我国《国家网络空间安全战略》《网络安全法》《网络安全等级保护2.0》等一系列政策/法规/标准的持续落地&#xff0c;网络安全行业地位、薪资随之水涨船高。 未来3-5年&#xff0c;是安全行业的黄金发展期&#xff0c;提前踏入…

2024 手把手教你MathType 7.8中文破解版详细安装激活图文教程

MathType 7.8中文破解版是一款全球最受欢迎的专业数学公式编辑器工具软件,MathType可视化公式编辑器轻松创建数学方程式和化学公式.兼容Office Word,PowerPoint,Pages,Keynote,Numbers等700多种办公软件,用于编辑数学试卷,书籍,报刊,论文,幻灯演示等文档轻松编写各种复杂的物理…

手机怎么下载别人直播间视频

手机下载直播视频&#xff0c;您需要按照以下步骤进行操作&#xff1a; 1. 打开直播平台&#xff0c;获取正在直播的链接&#xff0c;就是直播间的地址&#xff0c;然后粘贴在直接视频解析工具里&#xff0c;就可以同步下载直播视频画面。 2. 获取直播视频解析工具方法&#…

bcb6 lib编程

Library 新建 Library 新建Cpp File File1.cpp extern "C" __declspec(dllexport) int add(int a,int b) {return ab;}Build Project->Build Project1 使用 新建项目 Add New Project Unit1.cpp #pragma hdrstop#include "Unit1.h" //---------…

python文件操作常用方法(读写txt、xlsx、CSV、和json文件)

引言 用代码做分析的时候经常需要保存中间成果&#xff0c;保存文件格式各不相同&#xff0c;在这里好好总结一下关于python文件操作的方法和注意事项 Python 提供了丰富的文件操作功能&#xff0c;允许我们创建、读取、更新和删除文件。允许程序与外部世界进行交互。 文章目录…

Java:使用BigDecimal、NumberFormat和DecimalFormat保留小数

一、代码和调试结果 1.1 BigDecimal ![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/fa36749de8124266a730817710fdf737.png) 1.2 DecimalFormat 1.3 NumberFormat 二、原代码 BigDecimalUtil.java 代码 package utils;import java.math.BigDecimal; import jav…

容联云零代码平台容犀desk:重新定义坐席工作台

在数智化浪潮的推动下&#xff0c;企业亟待灵活适应市场变化、快速响应客户需求&#xff0c;同时还要控制成本并提升效率&#xff0c;传统的软件开发模式因开发周期长、成本高、更新迭代慢等问题&#xff0c;逐渐难以满足企业灵活多变的业务需求。 容犀Desk&#xff0c;观察到…

(保姆级教程傻瓜式操作)树莓派--基于opencv实现人脸识别

前言 因为当时没有边实验边记录&#xff0c;所以这篇文章可能存在疏漏。不过很多地方我推荐了我参考过的博客或者视频&#xff0c;希望尽可能地解答您的疑惑&#xff0c;如果您仍有不懂的地方&#xff0c;欢迎评论&#xff0c;如果我知道答案&#xff0c;我会很乐意为您解答。 …

使用人人开源renren-fast快捷搭建后台管理系统

https://gitee.com/renrenio/renren-fast https://gitee.com/renrenio/renren-fast 初始化项目数据库 导入项目运行 期间遇到的坑 024-04-25 01:30:27.638 ERROR 25228 --- [ main] com.alibaba.druid.pool.DruidDataSource : init datasource error, url: jdbc:…

UIKit之图片浏览器

功能需求 实现一个图片浏览器&#xff0c;点击左右按钮可以切换背景图&#xff0c;且更新背景图对应的索引页和图片描述内容。 分析&#xff1a; 实现一个UIView的子类即可&#xff0c;该子类包含多个按钮。 实现步骤&#xff1a; 使用OC语言&#xff0c;故创建cocoa Touch类…

运用MongoDB Atlas释放开发者潜能同时把控成本

在当下的商业环境中&#xff0c;不可预测性已经成为常态&#xff0c;工程团队负责人必须在把控不可预测性和优化IT成本的双重挑战下谋求平衡。 咨询公司德勤2024 MarginPLUS调查收集了300多位企业负责人的见解&#xff0c;报告中重点介绍了面对动荡的全球经济环境&#xff0c;…