【C++】理解C++中的复制、复制构造函数

news2025/1/12 21:35:59

十、理解C++中的复制、复制构造函数

拷贝就是要复制数据,也就是复制内存。
当我们把一个对象或一段数据从一个地方拷贝到另一个地方,那这个对象或数据其实是有两个副本,而且这个过程还是需要时间和开销的。所以如果你只是想读取数据,那你就要尽量避免拷贝;如果你还需要修改已经存在的数据,而且还想保留源数据,此时才需要拷贝。总之就是要避免不必要的拷贝,因为这会浪费性能。所以从底层了解复制是如何运作的,才可以避免不必要的浪费,才能高效正确的编写C++代码。

本篇先讲什么是copy,然后手写一个字符串复制的类,揭开拷贝的本质,就是拷贝都做了什么工作,并从中引出什么是浅拷贝、深拷贝。然后再从深拷贝引出复制构造函数,最后总结什么时候该拷贝什么时候不需要拷贝,不需要拷贝时如何阻止或者减少拷贝,让你的程序运行更快。因为有些拷贝不仅仅是复制点数据、浪费几个cpu周期,而是彻头彻尾的不需要。

1、展示三个copy的例子:

可见除了引用外,只要你是赋值=号就基本上就是copy了。

2、自己手动写一个字符串复制的类,看看copy是如何实现的:

从上图可见,我们实现copy就是一个个字符的拷贝,把常量区的字符串复制一份到堆中。下面我再以打断点的方式,看看是不是内存中确实是“liyuanyuan”和"LiyuanyuanE"是分别存储在两个地方:

此处的内容如果还有疑问,可参考 【C++】深度理解C++数据类型:常量、变量、数组、字符串、指针、函数_c++ 字符串常量-CSDN博客 中的字符串字面量部分,你会更加清晰。

3、浅拷贝、深拷贝
但是上图的代码是初始化一个对象a,如果我们用=号赋值一个对象呢?就是用=号能不能复制一个对象b?如下图所示我这样写main函数: 

很不幸,当我们用=号复制时,就出现了崩溃!
为什么会出现上面的异常?那是因为,当我们把对象a赋值给对象b时(上图A处),对象a的其实不是"liyuanyuanE"这个字符串数组本身。对象a只是{p, m_size},就是对象a在内存中存储的是一个指针p和一个unsigned int类型的m_size。所以我们A处其实就是把p和m_size拷贝给了b。也所以打印b其实打印的是b.p,而a的p和b的p的值都一样,都是指向堆上的同一块儿内存。也所以当b修改了第一个元素为L,a打印出来其第一个元素也被修改了。也所以当代码执行到B处,先释放对象b时,就已经调用了析构函数删除了堆上的字符串数组了,再释放对象a时,又得调用析构函数,此时a中的p的值指向的堆内存已经被标记为free状态了,你再调析构函数free那块内存就没法free了,于是报了_UNKOWN_BLOCK。

从这个崩溃中我们可以看出:除了引用赋值,其他赋值我们都可以称为复制,但是有的是复制本体,比如对象a就是真真切切把常量区的字符串复制了一份到堆区;而有的则是复制了一个指向这个对象的指针!,比如对象b复制的不是a的堆中的字符串数组,而是栈中的a的本体:一个指针p一个无符号整型m_size。所以,我们称a的复制就是深拷贝;b的复制就是浅拷贝。二者都是拷贝,但是一个拷贝了本体,一个拷贝了指向本体的指针,而没有拷贝指针指向的内容。

那如何让上面的b也真真切切的拷贝一份字符串而非一个指向字符串的指针呢?你可以依然用函数或者方法去写,让b也返回的是一个新字符串,但是这里我们不介绍这种方法,我们介绍另外一种方法:如何写复制构造函数

4、复制构造函数
复制构造函数也是一个构造函数,当你复制第二个字符串时,它会被重载。当你把一个字符串赋值给另一个字符串对象时,就是当你试图创建一个新的变量并给它分配另一个同类型变量时,你复制这个变量时,就会自动调用拷贝构造函数。C++默认情况下会为我们提供一个复制构造函数,但是这里我们先自己手动写一个简易版的,看看它是怎么运行的。
ps,此时你明白了我为何不用C++自带的string库了嘛,因为如果我使用了,很多东西就被在我们看不见的地方自动化执行了,我们就看不到事物的本来面貌了。

至此,我们的程序就正常工作了,不会出现a,b互相影响的情况,也不会出现程序崩溃的现象,程序成功终止。

5、想复制就复制吗?
当我们把上面的代码中的cout全部用一个函数代替时:

可见,不是任何时候我们都需要拷贝的,上例中的func函数,调用了3次,就拷贝了3次参数,调用完毕还得销毁,所以也销毁了3次。要知道每次拷贝都是要在堆上另辟一块内存,一个个字符逐个写入的。而func仅仅是读一下打印出来,然后还得销毁。这岂不是非常浪费吗?完全没必要这样做啊!我们可以这样做:

上面的做法就是想告诉我们always alwayst一定要通过const引用去传递对象。因为在基础使用中,const引用更好。即使你在函数内部想复制参数,那你就在函数内部复制,不需要到处复制,到处复制会拖慢你的程序。

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

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

相关文章

SQL使用IN进行分组统计时如何将不存在的字段显示为0

这两天被扔过来一个脏活儿:做一个试点运行系统的运营指标统计。 活儿之所以称为“脏”,是因为要统计8家单位共12个项目的指标。而每个项目有3个用户类指标,以及分17个功能模块,每个功能模块又分5个维度的指标。也就是单个项目是1…

携手Vatee万腾平台,共赴智能时代新征程

在科技日新月异的今天,我们正站在一个前所未有的历史交汇点上——智能时代的大门已轰然洞开,万物互联、数据驱动、智能决策正逐步成为社会发展的新常态。在这场深刻的变革中,Vatee万腾平台以其前瞻性的视野、创新的技术实力以及深厚的行业积淀…

QtCreator学习(二).在stm32mp1中使用

0.配置编译环境 复制【正点原子】STM32MP157开发板(A盘)-基础资料\05、开发工具\01、交叉编译器st-example-image-qtwayland-openstlinux-weston-stm32mp1-x86_64-toolchain-3.1-snapshot.sh到虚拟机chmod添加可执行文件,./st*运行&#xff…

信号与线性系统综合实验

文章目录 一、实验目的二、实验内容及其结果分析(一)基础部分(二)拓展部分(三)应用设计部分 三、心得体会 一、实验目的 1、掌握连续时间信号与系统的时域、频域综合分析方法;   2、掌握运用M…

【数据库】MySQL-基础篇-多表查询

专栏文章索引:数据库 有问题可私聊:QQ:3375119339 目录 一、多表关系 1.一对多 2.多对多 3.一对一 二、多表查询概述 1.数据准备 2.概述 3.分类 三、内连接 1.隐式内连接 2.显式内连接 3.案例 四、外连接 1.左外连接 2.右外连…

力扣最热一百题——轮转数组

目录 题目链接:189. 轮转数组 - 力扣(LeetCode) 题目描述 示例 提示: 知识补充ArrayDeque () ArrayDeque 的特点: 常用方法: 详细示例: 运行结果: …

无刷直流电动机的匝间绝缘测试优化

近年来,随着消费者对高效、快速干发需求的增加,高速电吹风逐渐成为市场的宠儿。高速电吹风的关键技术之一便是无刷直流电动机,其转速可以高达100,000转/分钟以上,电压为DC310V。相比传统电吹风,高速电吹风在效率和用户…

java基于PDF底层内容流的解析对文本内容进行编辑

本文实现了基于坐标位置对PDF内容的底层修改而非覆盖,因此不会出现在某些高级PDF编辑器中可以移除插入内容或者文件随着编辑次数增多而大幅增大(原因是原内容还在文件中)的问题,而且使用的pdfbox是一个开源的、免费的PDF处理库&am…

如何使用 Vidu Studio 根据照片和提示词生成视频

在这个数字化时代,视频内容已经成为我们日常生活中不可或缺的一部分。无论是记录美好瞬间,还是制作创意短片,视频都能生动地呈现我们的故事。今天,我将向大家介绍如何使用 Vidu Studio,根据已有照片和提示词&#xff0…

保姆级CVE-2018-17066漏洞复现 DLink命令注入漏洞(更新完结)

参考文章 CVE-2018-17066复现-CSDN博客 IOT-CVE-2018-17066(D-Link命令注入漏洞)_firmae路由仿真-CSDN博客 https://www.cnblogs.com/from-zero/p/13300396.html IOT-CVE-2018-17066(D-Link命令注入漏洞)_iot设备漏洞-CSDN博客 cve-2018-17066复现 | 1uckycs blog 漏洞环境搭建…

web渗透—RCE

一:代码执行 相关函数 1、eval()函数 assert()函数 (1)原理:将用户提交或者传递的字符串当作php代码执行 (2)passby:单引号绕过:闭合注释;开启GPC的话就无法绕过(GPC就是将单引号转换为"反斜杠单引号"&a…

【Redis】缓存和数据库一致性问题及解决方案

往期文章: 【Redis】Redis 底层的数据结构(结合源码) 【Redis】为什么选择 Redis 做缓存? 【Redis】缓存击穿、缓存穿透、缓存雪崩原理以及多种解决方案 一、前言 在前面的文章中,我们探讨了为什么要使用 Redis…

独居打工人,把超市当顶配食堂

文 | 螳螂观察 作者 | 如意 独自在大城市扎根的年轻人有着自己的小确幸,比如“周末可以睡到下午才起床,不会有任何人打扰”,“瘫在沙发上吃着零食享受一部自己想看很久的电影,也不会被唠叨。” 但生活并不总是尽如人意&#xf…

基于SpringBoot+Vue的学生宿舍水电信息管理系统

作者:计算机学姐 开发技术:SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等,“文末源码”。 专栏推荐:前后端分离项目源码、SpringBoot项目源码、SSM项目源码 系统展示 【2025最新】基于JavaSpringBootVueMySQL的…

PDF在线编辑哪家强?2024年4款热门工具大比拼

如今是数字化的时代,PDF 文件对我们工作和学习来说特别重要。不过呢,遇到那些麻烦的 PDF 编辑和转换的事情时,你是不是常常觉得没招儿,甚至还得加班到半夜?别犯愁啦,今天我给你讲讲四款非常好用的 PDF 在线…

深入理解全连接层:从线性代数到 PyTorch 中的 nn.Linear 和 nn.Parameter

文章目录 数学概念(全连接层,线性层)nn.Linear()nn.Parameter()Q1. 为什么 self.weight 的权重矩阵 shape 使用 ( out_features , in_features ) (\text{out\_features}, \text{in\_features}) (out_features,in_features)而不是 ( in_featur…

【人工智能】OpenAI最新发布的GPT-o1模型,和GPT-4o到底哪个更强?最新分析结果就在这里!

在人工智能的快速发展中,OpenAI的每一次新模型发布都引发了广泛的关注与讨论。2023年9月13日,OpenAI正式推出了名为o1的新模型,这一模型不仅是其系列“推理”模型中的首个代表,更是朝着类人人工智能迈进的重要一步。本文将综合分析…

10款超好用的电脑文件加密软件推荐|2024文件加密软件排行榜

在数字时代,数据安全已成为个人和企业不可忽视的重要议题。加密软件作为守护数据安全的坚固防线,其重要性不言而喻。以下是2024年备受推荐的十款电脑文件加密软件。 1.安秉网盾 安秉网盾以其全面的数据保护和安全防护功能备受企业青睐。它支持多种加密…

C语言内存函数(21)

文章目录 前言一、memcpy的使用和模拟实现二、memmove的使用和模拟实现三、memset函数的使用四、memcmp函数的使用总结 前言 正文开始,发车! 一、memcpy的使用和模拟实现 函数模型:void* memcpy(void* destination, const void* source, size…

深入Redis:分布式锁

在一个分布式的系统中,会涉及到多个节点访问同一个公共资源的情况。此时就需要通过锁来做互斥控制,避免出现类似于“线程安全”的问题。 Java中的synchronize只能在当前线程中生效,在分布式的这种多个进程多个主机的场景下就无能为力了。此时…