C++之深拷贝和浅拷贝

news2024/11/24 15:07:11

目录

浅拷贝

深拷贝

赋值运算符重载的深拷贝


在学习C++类和对象时我们学习了浅拷贝,本期我们将再次回顾浅拷贝并为大家讲述深拷贝的概念。

浅拷贝

在学习类和对象时我们学习了拷贝构造函数的概念,而且我们也知道,因为拷贝构造函数属于类的默认成员函数吗,所以当我们没有显示定义拷贝构造函数时,编译器会生成拷贝构造函数,编译器生成的拷贝构造函数对内置类型成员变量会完成字节序的值拷贝,对于自定义类型会去调用其拷贝构造函数。这里对内置类型成员变量进行的字节序值拷贝我们就称作浅拷贝,为什么我们我们要称字节序的值拷贝为浅拷贝呢?

我们通过依然自定义的string类中的拷贝构造函数为大家讲解:

代码如下:

class string
	{
	public:
		string(const char* str)
			:_str(new char[strlen(str) + 1])
		{
			strcpy(_str, str);
		}
		~string()
		{
			delete [] _str;
			_str = nullptr;
		}
	private:
		 char* _str;
	
	};

	void test1()
	{

		string s1("hello yjd");
		//调用拷贝构造函数
		string s2(s1);
        //调用赋值运算符重载
        string s3("hello world");
        s3 = s1;
	}

如上代码,我们自己定义了一个string类,string类由于我们没有声明拷贝构造函数,所以编译器会生成默认的拷贝构造函数,但是生成的默认的拷贝构造函数会对内置类型进行值拷贝,就会将s1对象的_str成员变量的值传给s2对象的_str成员变量。

所以就会导致下面这种情况,图示如下: 

运行截图如下:

不难发现,编译器提示我们出现了错误,这是因为编译器默认生成的拷贝构造函数对于内置类型是值拷贝,所以s1._str的值会赋给s2._str,就会导致两个指针变量指向了统一块动态申请的空间,既然是动态申请的空间在最后为了防止内存泄漏肯定是要使释放的,因为两个对象在小销毁之前都会调用析构函数进行资源的清理,所以这就会导致统一块空间被释放了两次,这边会导致错误,所以为了防止这种情况的出现,在此情境下诞生了深拷贝。 

深拷贝

什么是深拷贝,说白了深拷贝就是为了解决在堆上申请的空间被释放两次的问题,针对上述浅拷贝所产生的现象,为了防止两个指针指向了同一块空间,我们可以先让s2在堆上申请与s1大小相同的空间,在C语言中我们学习了字符串函数strcpy,我们可以通过这个函数实现两个字符串值的传递。

图示如下:

通过图示,不难发现,两个对象的成员变量指向了两个不同的空间,所以此时我们也就不用担心在堆区开辟的空间被释放两次的问题,所以深拷贝就解决了浅拷贝中所带来的不足。

代码如下:

	string(string& s)
			:_str(new char[strlen(s._str)+1])
		{
			strcpy(_str, s._str);
		}

上述代码便是我们自己生成的拷贝构造函数代码,所以在今后学的的数据结构只要需要在堆上动态开辟空间,我们就需要自己定义拷贝构造函数。

赋值运算符重载的深拷贝

在学习类和对象时我们也学习了赋值运算符重载,赋值运算符重载和拷贝构造函数的区别是:

1.拷贝构造函数是用一个已经存在的对象初始化一个刚刚创建的对象。

2.赋值运算符重载是两个已经存在的对象之间进行赋值。

图示如下:

解析:因为赋值运算符重载也属于类的成员函数,当我们没有显示定义赋值运算符重载时,编译器也会默认生成一个赋值运算符重载,但是默认生成的赋值运算符重载和默认生成的拷贝构造函数是类似的,对于内置类型的成员变量,会完成字节序的值拷贝(浅拷贝),通过默认拷贝构造函数我们知道,浅拷贝是存在弊端的,所以对于在堆上开辟空间的数据结构,我们必须自己显示定义赋值运算符重载。

        其实整个过程和拷贝构造函数类似,不过赋值运算符重载我们要先释放掉原来的空间,释放掉原来的空间之后,在动态开辟一块与s1大小相同的空间,然后将这块空间的地址传给s3._str,然后通过strcpy函数实现字符串值的拷贝。

代码如下:

string& operator=(string& s)
		{
			if (this != &s)
			{
				char* tmp = new char[strlen(s._str) + 1];
				strcpy(tmp, s._str);
				delete[]_str;
				_str = tmp;
			}
			return *this;

		}

截图如下:

注意,代码中我们有两个需要注意的地方:

1.自己不需要给自己赋值,所以直接返回自身即可。

2.为了避免申请空间失败仍然释放掉原来空间的这种情况,我们定义了一个中间变量tmp,当空间申请失败时,我们则不释放原来的空间,当空间申请成功时,我们先赋值给临时字符串tmp,最后再将临时字符串赋值给成员变量_str就可以完成赋值运算符重载。

好了,深拷贝和浅拷贝的内容到这里就全部结束了,我们本次为大家带来的是传统版本的深拷贝,后期会为大家讲述效率更高的的深拷贝的方法。 

本期内容到此结束^_^

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

02|用LangChain快速构建基于“易速鲜花”本地知识库的智能问答系统

02|用LangChain快速构建基于“易速鲜花”本地知识库的智能问答系统 项目及实现框架 我们先来整体了解一下这个项目。 项目名称:“易速鲜花”内部员工知识库问答系统。 项目介绍:“易速鲜花”作为一个大型在线鲜花销售平台,有自…

SpringCloudGateway网关处拦截并修改请求

SpringCloudGateway网关处拦截并修改请求 需求背景 老系统没有引入Token的概念,之前的租户Id拼接在请求上,有的是以Get,Param传参形式;有的是以Post,Body传参的。需要在网关层拦截请求并进行请求修改后转发到对应服务。…

软件工程快速复习(期末急救)

每个同学要假想自己是一个项目经理,去完成一个软件项目,比如医院管理系统,自动设备控制系统等,以面向结构的软件工程方法,说出完成项目的步骤,涉及到的具体技术。初步了解面向对象的方法的与面向结构的方法…

Linux网络编程——字节序

一、概念 字节序是指多字节数据在计算机内存中存储或者网络传输时各字节的存储顺序。 二、分类 字节序有两者常见序: 1. Big-Endian(大端):高位字节排放在内存的低地址端,低位字节排放在内存的高地址端。如&#x…

量化交易学习笔记:XGBoost 在量化选股中的应用

一、引言 本篇文章通过借鉴传统机器学习算法——XGBoost——对相同的量价因子进行实验,方便与深度学习模型进行对比实践。 二、算法介绍 XGBoost 是在 Gradient Boosting(梯度提升)框架下实现的机器学习算法,全称为“极限梯度提…

图神经网络并在 TensorFlow 中实现

asokraju.medium.com 一、说明 本文将引导您了解图神经网络 (GNN) 并使用 TensorFlow 实现该网络。在后续的 文章中,我们讨论 GNN 的不同变体及其实现。这是一个分步计划: 图神经网络 (GNN) 的使用:我们首先讨论 GNN 是什么、它们如何工作以及…

论文阅读<MULTISCALE DOMAIN ADAPTIVE YOLO FOR CROSS-DOMAIN OBJECT DETECTION>

论文链接:https://arxiv.org/pdf/2106.01483v2.pdfhttps://arxiv.org/pdf/2106.01483v2.pdf 代码链接:GitHub - Mazin-Hnewa/MS-DAYOLO: Multiscale Domain Adaptive YOLO for Cross-Domain Object DetectionMultiscale Domain Adaptive YOLO for Cross…

[JS设计模式]Command Pattern

文章目录 举例说明优点缺点完整代码 With the Command Pattern, we can decouple objects that execute a certain task from the object that calls the method. 使用命令模式,我们可以将执行特定任务的对象与调用该方法的对象解耦。 怎么理解 执行特定任务的对…

【SpringBoot】之Security进阶使用

🎉🎉欢迎来到我的CSDN主页!🎉🎉 🏅我是君易--鑨,一个在CSDN分享笔记的博主。📚📚 🌟推荐给大家我的博客专栏《SpringBoot开发之Security系列》。&#x1f3af…

解决 Linux git push 贡献者不同(没有出现绿点)的问题

第一步,通过下面的指令,修改 linux git 的配置文件: vi ~/.gitconfig会进入下图界面: 进入本地(Windows)中 git 的设置界面 复制 名称 和 Email 到 gitconfig 里,不要在末尾加 (空…

直排轮滑教程4

蹬地 1,前面练习了蹬地的结构,知道蹬地方向,如何用力。下面来练习具体的蹬地的方法,轮滑蹬地有自己特点。 2,技术方法和特点:蹬地速度快,蹬地有弹性。似跳非跳蹬。 3,四轮着地。轮…

使用PE信息查看工具和Beyond Compare文件比较工具排查dll文件版本不对的问题

目录 1、问题说明 2、修改了代码,但安装版本还是有问题 3、使用PE信息查看工具查看音视频库文件(二进制)的时间戳 4、使用Beyond Compare比较两个库文件的差异 5、找到原因 6、最后 C软件异常排查从入门到精通系列教程(专栏…

NFS原理详解

一、NFS介绍 1)什么是NFS 它的主要功能是通过网络让不同的机器系统之间可以彼此共享文件和目录。 NFS服务器可以允许NFS客户端将远端NFS服务器端的共享目录挂载到本地的NFS客户端中。 在本地的NFS客户端的机器看来,NFS服务器端共享的目录就好像自己的磁…

【蓝桥杯】树的重心

树的重心 图的dfs模板 int dfs(int u) {st[u]true;for(int ih[u];i!-1;ine[i]){int je[i];if(!st[j]){dfs(j);}} }树是这样的。 邻接表: 1: 4->7->2->-1 2: 5->8->1->-1 3: 9->4->-1 4: 6->3->1->-1 5: 2->-1 6: 4->-1 7…

计算机网络 运输层下 | TCP概述 可靠传输 流量控制 拥塞控制 连接管理

文章目录 3 运输层主要协议 TCP 概述3.1 TCP概述 特点3.2 TCP连接RSVP资源预留协议 4 TCP可靠传输4.1 可靠传输工作原理4.1.1 停止等待协议4.1.2 连续ARQ协议 4.2 TCP可靠通信的具体实现4.2.1 以字节为单位的滑动窗口4.2.2 超时重传时间的选择4.2.3 选择确认SACK 5 TCP的流量控…

Python---socket之send和recv原理剖析

1. 认识TCP socket的发送和接收缓冲区 当创建一个TCP socket对象的时候会有一个发送缓冲区和一个接收缓冲区,这个发送和接收缓冲区指的就是内存中的一片空间。 2. send原理剖析 send是不是直接把数据发给服务端? 不是,要想发数据,必须得…

GEE-Sentinel-2月度时间序列数据合成并导出

系列文章目录 第一章:时间序列数据合成 文章目录 系列文章目录前言时间序列数据合成总结 前言 利用每个月可获取植被指数数据取均值,合成月度平均植被指数,然后将12个月中的数据合成一个12波段的时间数据合成数据。 时间序列数据合成 代码…

嵌入式中断理解

一、概念 中断: 在主程序运行过程中,出现了特定的中断触发条件(中断源),使得CPU暂停当前正在运行的程序,转而去处理中断程序,处理完成后又返回原来被暂停的位置继续运行。 中断优先级&#x…

YACS(上海计算机学会竞赛平台)一星级题集——水仙花指数

题目描述 定义一个正整数的十进制表示中各位数字的立方和为它的水仙花指数,给定一个整数 n,请计算它的水仙花指数。 例如 n1234 时,水仙花指数为 输入格式 单个整数:表示 n 输出格式 单个整数:表示 n 的水仙花指…

IPC之九:使用UNIX Domain Socket进行进程间通信的实例

socket 编程是一种用于网络通信的编程方式,在 socket 的协议族中除了常用的 AF_INET、AF_RAW、AF_NETLINK等以外,还有一个专门用于 IPC 的协议族 AF_UNIX,IPC 是 Linux 编程中一个重要的概念,常用的 IPC 方式有管道、消息队列、共…