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.mfbz.cn/a/629443.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Gemini 5.14日更新 - 推出Gemini Advance服务

收到Gemini Advance试用邀请 今天和往常一样&#xff0c;打开Gemini&#xff0c;惊喜的发现右小角一行小字&#xff1a;试用Gemini Advance。好家伙&#xff0c;OpenAI 刚推出ChatGPT 4o&#xff0c;Google立马推出Gemini Advance&#xff0c;说明国外高科技企业也是很拼的。 …

STC8增强型单片机开发【热敏电阻】

目录 一、引言 二、热敏电阻概述 三、STC8增强型单片机简介 四、基于STC8单片机的热敏电阻测温系统 五、热敏电阻测温系统的优化与扩展 提高测量精度 扩展系统功能 六、 温度计算步骤 通过ADC采样计算出热敏电阻位置的电压 通过欧姆定律计算热敏电阻的阻值 通过阻值…

【Linux】常用指令、热键与权限管理

一、常用指令 &#xff08;1&#xff09;ls 功能&#xff1a;列出指定目录下的所有子目录与文件 用法&#xff1a;ls &#xff08;选项&#xff09; &#xff08;目录或文件名&#xff09; 常用选项&#xff1a; -a&#xff1a;列出目录下的所有文件&#xff0c;包括隐藏…

fastjson1.2.68对于文件操作的分析最全

fastjson1.2.68对于文件操作的分析 前言分析复制文件写入文件读取文件分析poc拓宽场景极限环境poc优化修改再次优化poc的分析 前言 这次分析也是分析了很久&#xff0c;因为每个链子都是自己去跟着分析了的&#xff0c;然后主要是去学习了一下怎么去挖链子 分析 前面漏洞复现…

TypeScript中的泛型(Generics)

TypeScript中的泛型&#xff08;Generics&#xff09; 在前面的几篇文章中&#xff0c;我们了解了TypeScript的类、接口和基本的数据类型系统。本文将重点介绍TypeScript中的泛型&#xff0c;这是一种强大的工具&#xff0c;它允许我们创建可重用的组件&#xff0c;同时保持类…

【Java学习笔记10 Java Web 应用——JSP

JSP(Java Script Pages)技术是一种网站开发技术&#xff0c;可以让Web开发人员快速、高效的开发出易于维护的动态网页。使用JSP技术开发的Web应用程序具有跨平台性&#xff0c;不需要修改程序&#xff0c;发布后即可在Windows、Linux等不同的操作系统中运行。 10.1 JSP技术概述…

申请免费通配符证书

通配符证书是一种 SSL/TLS 证书&#xff0c;可用于保护多个域&#xff08;主机&#xff09;&#xff0c;由域名字段中的通配符 (*) 指示。这种证书主要用于具有许多子域的组织。通配符证书对主域及其所有次级子域有效。 通配符证书和多域名证书的区别&#xff1a; 要注意的是…

webpack优化构建速度示例-合理配置loader的include exclude:

实际上&#xff0c;babel-loader 在 Webpack 配置中默认并不包含 exclude 和 include 选项的默认值&#xff0c;通常&#xff0c;为了优化构建性能&#xff0c;开发者会显式地设置 exclude 和 include 选项&#xff0c;以便 babel-loader 只处理必要的文件。 src/index.js impo…

Zookeeper and RPC dubbo

javaguide zookeeper面试题 Zookeeper 啥是Zookeeper干啥的 ZooKeeper 可以被用作注册中心、分布式锁&#xff1b; ZooKeeper 是 Hadoop 生态系统的一员&#xff1b; 构建 ZooKeeper 集群的时候&#xff0c;使用的服务器最好是奇数台。 启动ZK 下载安装解压 不过多赘述 我的…

Spring:了解@Import注解的三种用法

一、前言 在 Spring 框架中&#xff0c;Import 注解用于导入配置类&#xff0c;使得你可以在一个配置类中引入另一个或多个配置类&#xff0c;从而实现配置的模块化。这对于组织大型应用程序的配置非常有用&#xff0c;因为它允许你将配置分散到多个类中&#xff0c;然后再将它…

RAW转换和图像编辑工具:Capture One 23 Pro (win/mac)中文专业版

Capture One 23是一款功能强大的桌面版照片编辑软件&#xff0c;由丹麦PHASE ONE飞思数码公司开发。 以下是该软件的一些主要特点&#xff1a; 强大的RAW处理功能&#xff1a;Capture One 23支持多种品牌的相机和镜头&#xff0c;提供了丰富的RAW处理工具&#xff0c;包括曝光、…

RALL-E: Robust Codec Language Modeling with Chain-of-Thought Prompting for TTS

demo pageDetai Xin&#xff0c; tanxu微软 & 东大 & 浙大 abstract 使用CoT的思路&#xff0c;和Valle的框架&#xff0c;先实现LLM预测音素级别pitch/duration&#xff0c;然后预测speech token。 methods Prosody tokens as chain-of-thought prompts 和Valle一…

【JavaEE】Servlet

文章目录 一、Servlet 是什么二、如何创建Servlet程序1、创建项目2、引入依赖3、创建目录4、编写代码5、打包程序6、部署程序7、验证程序 一、Servlet 是什么 二、如何创建Servlet程序 1、创建项目 2、引入依赖 Maven 项目创建完后&#xff0c;会自动生成一个 pom.xml 的文…

独家|暴雨推出基于国产X86芯片的四路服务器

伴随着智慧计算时代的到来和企业数字化转型的深入&#xff0c;人工智能、大数据、虚拟化等创新技术在应用普及的过程中&#xff0c;也在不断地细分和深化&#xff0c;使得企业的业务系统日趋复杂&#xff0c;数据量、数据类型更加庞大&#xff0c;对计算平台的性能要求“水涨船…

Google I/O 2024:探索未来AI技术的无限可能

近日&#xff0c;Google I/O 2024大会圆满落幕&#xff0c;带给我们一场关于人工智能的盛宴。在这场大会上&#xff0c;Google推出了一系列令人激动的AI新功能和工具&#xff0c;让我们得以一窥未来的科技发展。今天&#xff0c;就让我来为大家总结一下这些亮点吧&#xff01; …

一键修复所有dll缺失,教大家解决丢失的dll文件

修复所有DLL&#xff08;动态链接库&#xff09;文件缺失的问题通常不可能通过单一的"一键修复"按钮来实现&#xff0c;因为DLL文件缺失可能由各种不同的原因导致&#xff0c;比如应用程序安装不正确、病毒感染、或系统文件损坏等。 使用内置的系统文件检查器&#x…

鸿蒙应用布局ArkUI【基础运用案例】

布局基础运用案例 平级导航的复合网格视图 平级导航的复合网格视图常出现在同时展示多种不同内容的界面。 例如&#xff0c;市场类应用作为典型的平级导航&#xff0c;其首页不同板块采用了不同布局能力。 标题栏与搜索栏&#xff1a;因元素单一、位置固定在顶部&#xff0c…

C++ 中重写重载和隐藏的区别

重写&#xff08;override&#xff09;、重载&#xff08;overload&#xff09;和隐藏&#xff08;overwrite&#xff09;在C中是3个完全不同的概念。我们这里对其进行详细的说明 1、重写&#xff08;override&#xff09;是指派生类覆盖了基类的虚函数&#xff0c;这里的覆盖必…

【JAVA SE】初识JAVA

✨✨欢迎大家来到Celia的博客✨✨ &#x1f389;&#x1f389;创作不易&#xff0c;请点赞关注&#xff0c;多多支持哦&#x1f389;&#x1f389; 所属专栏&#xff1a;JAVA 个人主页&#xff1a;Celias blog~ 目录 ​编辑 一、关于JAVA 1.1 JAVA语言简介 1.2 语言优势 1…

Patch-Wise Graph Contrastive Learning for Image Translation

Patch-Wise Graph Contrastive Learning for Image Translation 图像翻译中的逐块图对比学习 Chanyong Jung1, Gihyun Kwon1, Jong Chul Ye1, 2 Chanyong Jung&#xff0c;Gihyun Kwon&#xff0c;Jong Chul Ye 1, 2 Abstract 摘要 Patch-Wise Graph Cont…