string的深浅拷贝问题

news2024/11/28 5:37:58

深浅拷贝

  • 问题引入
  • 浅拷贝
  • 深拷贝
  • 总结

问题引入

对于一个普通的string类:

class String {
public:
	String(const char* str = "")
	{
		//构造函数
		if (nullptr == str)
			str = "";
		_str = new char[strlen(str) + 1];
		strcpy(_str, str);
	}
	~String()
	{
		//析构函数
		if (_str) {
			delete[] _str;
			_str = nullptr;
		}
	}
private:
	char* _str;
};

浅拷贝

对于上述的 String 类来说,浅拷贝也就是将一个对象原封不动的复制粘贴到新的对象当中,当类中没有给定拷贝构造函数时系统会默认生成一个拷贝构造函数,但默认生成的拷贝构造函数就属于浅拷贝:

在这里插入图片描述
当前系统默认生成的拷贝构造函数类似于:

在这里插入图片描述
那么,浅拷贝是否合理存在?

由上述运行截图我们可以观察到使用系统默认生成的拷贝构造函数或是代码中展现的拷贝构造方法构造出来的对象与原对象内容地址是完全一致的,也就类似于复制粘贴了一个相同的对象,那么它会产生什么问题?

在前边类与对象章节中,我们知道了在创建的类对象使用结束之后系统会自动调用相应的析构函数来释放资源空间(先构造的后释放,后构造的先释放),因此在该类中,首先要进行释放的是 s2,后释放 s1,我们来看看现象:

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

不知道,读者是否发现了问题所在?

解析

在使用 s2(s1),s1拷贝构造 s2 对象时,我们发现创建出来的 s2 对象完全是复制粘贴 s1 对象而形成的,不仅对象内容完全相同,对象的地址空间也完全相同,这就导致了两个对象是共享同一份地址空间了,故在进行析构时,产生了同一份地址空间二次释放而发生异常提示

在这里插入图片描述

同理,在 String 类中倘若用户没有显式定义赋值运算符重载函数,则系统会默认生成一个赋值运算符重载函数,我们来看看会有什么问题?

在这里插入图片描述
显然,同样产生了浅拷贝(复制粘贴),则在进行空间销毁时候定会产生空间的二次释放异常,那么我们应该如何来解决这种问题?

介绍两种技术:深拷贝(重点)、写时拷贝

深拷贝

产生浅拷贝的主要是因为在进行拷贝构造或是赋值运算符重载时,直接将就对象的内容原封不动的粘贴给新对象,因而在空间释放时形成了多次释放问题,因此深拷贝主要就是解决不同对象分配不同地址空间的问题:

String(const String& s):_str(nullptr)
	{
		//s2(s1)
		//首先需要给s2对象开辟一份独立的新空间
		_str = new char[strlen(s._str) + 1];
		//其次将s1对象中的内容拷贝到s2空间当中
		strcpy(_str, s._str);
	}

在这里插入图片描述

同理,赋值运算符也是一样的:

String& operator=(const String& s)
	{
		if (this != &s)  //判断不是自己给自己赋值
		{
			char* tmp = new char[strlen(s._str) + 1];
			strcpy(tmp, s._str);
			delete[] _str;  //释放旧空间
			_str = tmp;
		}
		return *this;
	}

在这里插入图片描述

显然,两个对象的地址空间是不相同的,则释放空间时不会发生同一份空间多次释放的问题。

现代新写法(注意理解)

String(const String& s):_str(nullptr)
	{
		//拷贝构造函数
		String tmp(s._str);  //采用当前对象的内容构造出一个新对象tmp
		swap(_str,tmp._str);   //进行资源交换,将临时空间 tmp 的内容与 当前对象的内容进行交换------------临时对象在函数周期结束自动析构释放
	}


	String& operator=(String s) {  //以值的方式传参,需要调用一次拷贝构造函数,构造出一个新的对象 s
		//赋值运算符重载
		if (this != &s) {
			swap(_str, s._str);   //直接进行交换
		}
		return *this;
	}

总结

在类中,倘若用户没有显式定义拷贝构造函数以及赋值运算符重载函数,则编译器会自动生成一份,但在使用时属于浅拷贝会造成同一份空间多个对象共享,在对象使用结束释放空间时会发生多次释放问题产生,其次在赋值运算符重载函数中,不仅会使得多个对象共享空间,还会导致空间丢失问题:

	String s1("hello");   //调用构造

	String s2 = "world";
	//使用系统默认生成的赋值运算符重载函数会导致原有的 s2 对象空间泄漏
	s2 = s1;

因此, 我们应该在使用时进行显式的定义,防止发生浅拷贝问题的产生

写时拷贝技术

写时拷贝技术同样是针对浅拷贝问题的解决方式

允许多个对象共享同一份地址空间以及空间中的内容,并定义一个计数器来统计当前空间所共享的对象个数,并在对象使用结束之后在析构函数内部进行计数器 - 1,当析构一个对象之后,计数器变为 0,说明当前对象是共享空间的最后一个使用者,则需要对这块空间进行释放--------------------------------但同样存在一个问题:倘若某一个对象对这块共享空间的内容进行了修改,则其他对象指向的这块共享空间内容也发生了变化

因此,写时拷贝技术是在对象需要对共享的内存空间进行修改时拷贝构造出独立的空间来进行修改,这么做就不会影响到其他对象对共享空间的访问。

ps:
博文内容为原创,欢迎各位共同学习~~

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

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

相关文章

CSGO搬砖项目,23年最适合小白的项目!

大家好,我是阿阳 不懂的小伙伴,咱继续听我娓娓道来 steam搬砖主要涉及的是csgo游戏平台装备的一个搬运,比较很好理解,主要就是道具的搬运工,简单来讲就是,从国外steam游戏平台购买装备,再挂到…

几种实现主题切换的方式

几种实现主题切换的方式 1. 利用 prefers-color-scheme 特性 prefers-color-scheme是CSS 媒体特性【media】用于检测用户是否有将操作系统的主题色设置为亮色【light】或者暗色【dark】。 当前prefers-color-scheme新特性支持各大主流电脑(window和IOS系统&#…

今天面试招了个18K的人,从腾讯出来的果然都有两把刷子···

公司前段时间缺人,也面了不少测试,前面一开始瞄准的就是中级的水准,也没指望来大牛,提供的薪资在15-20k,面试的人很多,但平均水平很让人失望。看简历很多都是4年工作经验,但面试中,不…

Jenkins使用(代码拉取->编译构建->部署上线)

Jenkins简介 Jenkins是一个开源项目,提供了一种易于使用的持续集成系统,使开发者从繁杂的集成中解脱出来,专注于更重要的业务逻辑实现上。同时Jenkins能实时监控集成中存在的错误,提供详细的日志文件和提醒功能,还能用…

HRMS有什么特点?

当今企业的发展离不开技术支持,同样,在管理方面也需要与时俱进,进行数字化转型。人力资源技术的运用是企业管理数字换转型的重要表现之一。在企业选择一款HR软件之前,应该先认识到,什么是人力资源管理软件——即HRMS。…

midjournery AI绘画使用指南

midjournery AI绘画使用指南 基于Discord的Midjournery配置: https://www.bilibili.com/video/BV16d4y1A7Zq/?spm_id_from333.337.search-card.all.click&vd_source9c3ca9555620bed64bdee27ae49d37cf 使用原则 使用midjournery绘画的原则是给出对脑海中某个…

golang rabbitMQ 生产者复用channel以及生产者组分发策略

引用的是rabbitMQ官方示例的库:github.com/rabbitmq/amqp091-go在网络编程中我们知道tcp连接的创建、交互、销毁等相关操作的"代价"都是很高的,所以就要去实现如何复用这些连接,并要做到高效并可靠。预期效果:项目初始化…

论如何用python自动下载爱的妹子视频~嘿嘿嘿~

前言 嗨喽,大家好呀~这里是爱看美女的茜茜呐 又到了学Python时刻~ 现在好看的妹子真的太多啦~ 如何一次性把这些好看的视频全保存下来捏? 开发环境: 版 本: python 3.8 编辑器: pycharm 2022.3.2 专业版 requests >>> pip install request…

【数据结构】复杂度讲解

目录 时间复杂度与空间复杂度:: 1.算法效率 2.时间复杂度 3.空间复杂度 4.常见时间复杂度以及复杂度OJ练习 时间复杂度与空间复杂度:: 什么是数据结构? 数据结构中是计算机存储,组织数据的方式,指相互之间存在一种或多种特定关…

面向对象的设计模式

"万丈高楼平地起,7种模式打地基",模式是一种规范,我们应该站在巨人的肩膀上越看越远,接下来,让我们去仔细了解了解面向对象的7种设计模式7种设计模式设计原则的核心思想:找出应用中可能需要变化之…

24考研|高等数学的基础概念定理(二)——第二章|导数与微分

文章目录一、基础概念定理部分1.1 导数的四则运算法则1.2 反函数的求导法则1.3 复合函数的求导法则1.4 费马引理1.5 罗尔定理1.6 拉格朗日中值定理1.7 导数为零的结论1.8 柯西中值定理1.9 洛必达法则1.10 泰勒中值定理(定理1,定理2)1.11 导数…

CRM系统能给企业带来什么? CRM系统推荐

什么是CRM系统? CRM系统(又称客户关系管理系统)是一个以客户为核心的管理软件,能有效改善企业与现有客户的关系,且帮助企业寻找新的潜在客户,并赢回以前老客户。 CRM系统能给企业带来什么? C…

计算机视觉框架OpenMMLab开源学习(五):目标检测实战

目标检测实战 前言:本篇主要偏向目标检测实战部分,使用MMDetection工具进行代码应用,最后对水果进行检测实战演示,本次环境和代码配置部分省略,具体内容建议参考前一篇文章:计算机视觉框架OpenMMLab开源学…

基于STM32设计的避障寻迹小车

一、前言 1.1 项目背景 根据美国玩具协会在一项研究中,过去几年全球玩具销售增长与GDP的世界平均水平大致相同。但全球玩具市场的内部结构已经占据了巨大的位置变化:传统玩具的市场份额正在下降,高科技电子玩具正在蓬勃发展。全球玩具市场的…

迁移至其他美国主机商时需要考虑的因素

网站的可访问性是关系业务的关键因素之一。一个稳定、快速且优化良好的主机上的网站更有可能享受不间断的流量,并在谷歌的SERP中获得更好的排名。因此,在构建企业网站时,选择合适的主机商相当重要。不过就以美国主机为例,由于每个…

three.js学习笔记(一):THREE.Materail五种基础材质的使用

MeshBasicMaterial(网格基础材质):基础材质,用于给几何体赋予一种简单的颜色,或者显示几何体的线框。MeshDepthMaterial(网格深度材质): 这个材质使用从摄像机到网格的距离来决定如何…

企业舆情监测多少钱,TOOM舆情监测专业服务平台

企业舆情监测的费用因公司不同而异,具体需要多少钱取决于您的需求和舆情监测公司的收费标准。一些因素,如舆情监测范围、数据收集方式、舆情分析报告等细节,都可能影响最终的费用。最好联系舆情监测公司询问具体收费标准。企业舆情监测多少钱…

Linux_用户和权限

一、认识root用户 --超级管理员 root用户拥有最大的系统操作权限,而普通用户在许多地方都是受限的 普通用户的权限,一般在其home目录内是不受限的 一旦出了home目录,大多数地方普通用户仅有只读和执行权限,无修改权限 1、su和…

linux配置密码过期的安全策略(/etc/login.defs的解读)

长期不更换密码很容易导致密码被破解,而linux的密码过期安全策略主要在/etc/login.defs中配置。一、/etc/login.defs文件的参数解读1、/etc/login.defs文件的内容示例[rootlocalhost ~]# cat /etc/login.defs # # Please note that the parameters in this configur…

10.jQuery中请求预处理 $.ajaxPrefilter()

在使用jQuery发起请求的时候($.get(),$.post().$ajax()都可以)会默认在请求前调用$.ajaxPrefilter()这个函数,我们可以利用这个来做一些事情 目录 1 定义API根路径 2 添加请求头 3 添加请求结束的回调函数 1 定义API根路径 这样后面每次请求就不用再写根路…