当前位置: 首页 > news >正文

C++之深拷贝进阶

目录

拷贝构造函数的深拷贝进阶版本

赋值运算符重载的深拷贝进阶

总结


上期我们学习了C++中深拷贝的传统版本,今天我们将学习更为高效的版本。

拷贝构造函数的深拷贝进阶版本

传统版本代码如下:

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

进阶版本代码如下:

string(string& s):_str(nullptr)
{string tmp(s._str);std::swap(_str, tmp._str);
}

注意:因为是初始化一个刚创建的对象,我们一定要哦将_str置空,否则其指向了一个未知的空间,等到刚创建的对象的_str成员变量和tmp对象的成员变量_str交换之后,因为未知的空间不是new出来的,所以无法进行释放,也就就会导致tmp._str在最终调用析构函数时会出错。 

图示如下:

解析:不难发现,进阶版本相比较于传统版本,进阶版本并没有像传统版本一样,申请空间之后调用和strcpy函数去进行字符串的拷贝,而是调用构造函数创建并初始化了一个对象tmp, 最终交换了成员变量的指针,从而使新创建的对象的成员指针指向了tmp._str指向的空间。

运行截图如下:

我们发现s1的值成功拷贝构造给了s2。 

赋值运算符重载的深拷贝进阶

传统版本代码如下:

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:

string& operator =(string &s){//为了避免自己给自己进行赋值if (this != &s){string tmp(s);std::swap(_str, tmp._str);}return *this;}

解析:进阶版本的区别是调用拷贝构造函数初始化了一个对象tmp,然后对这tmp对象和我们要进行赋值的对象的成员变量_str进行了交换,最终完成了赋值。 

 进阶版本2:

string& operator =(string s)
{std::swap(_str, s._str);return *this;
}

版本2和版本1的区别是什么?

版本1要考虑是否给自己赋值,但是版本2避开了这种情况,版本2的形参就是一个中间变量,我们通过拷贝构造函数用实参对其进行了初始化,此时的形参s和被赋值的对象根部就不可能是同一个对象,但是第1个版本的形参是引用类型,所以就会存在自身给自身赋值的情况。 

图示如下:

解析:通过图示我们可以看出来,赋值运算符重载的深拷贝的进阶版本实质上也是创建了一个中间对象,最终通过交换函数实现了两个对象的成员变量_str的交换从而实现了赋值,与拷贝构造函数的深拷贝的进阶版本不同的是,赋值运算符重载是针对两个已经存在的对象进行赋值,两个对象的指针交换之后,最终都会调用各自的析构函数完成资源的清理。 

运行截图如下: 

我们发现s1的值成功赋值给了s3。 

注意:不管是拷贝构造函数的进阶版本还是赋值运算符重载的进阶版本,其实本本质都是对函数的复用,拷贝构造函数深拷贝的进阶在创建对象时复用了构造函数。赋值运算符重载的深拷贝进阶复用了拷贝构造函数的深拷贝进阶,因为拷贝构造函数的深拷贝进阶又复用了构造函数,所以本质上,拷贝构造函数的赋值运算深拷贝进阶和符重载的深拷贝进阶都是复用了构造函数。 

总结

到了这里我们自己创建的string类的深拷贝和浅拷贝的全部知识已经全部学习完成了,目前的string类整个代码为:

namespace yjd
{class string{public://构造函数string(const char* str):_str(new char[strlen(str) + 1]){strcpy(_str, str);}//拷贝构造函数的深拷贝传统版本string(string& s):_str(new char[strlen(s._str) + 1]){strcpy(_str, s._str);}//赋值运算符重载的深拷贝传统版本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;}//拷贝构造函数的深拷贝进阶版本string(string& s):_str(nullptr){string tmp(s._str);std::swap(_str, tmp._str);}//赋值运算符重载的深拷贝进阶版本1string& operator =(string &s){//为了避免自己给自己进行赋值if (this != &s){string tmp(s);std::swap(_str, tmp._str);}return *this;}//赋值运算符重载的深拷贝进阶版本2string& operator =(string s){std::swap(_str, s._str);return *this;}~string(){delete [] _str;_str = nullptr;}private:char* _str;};
}

注意:以上整体代码有两个个需要注意的地方:

1.首先我们自定义了命名空间,不然就会和库中的string类产生冲突。

2.构造函数的形参的类型为const char*,因为const char*不仅可以接收常量字符串的地址,也可以接收字符数组类型的字符串地址,因为权限不变和权限缩小是可以的,而char*只可以接收数组类型的字符串,因为权限放大是不允许的,string类的字符串我们就可以定性为数组字符串,本质上就是一个数组。所以一般情况下我们用const char*类型去接收各种字符串的地址。

本期内容到此结束^_^ 

相关文章:

C++之深拷贝进阶

目录 拷贝构造函数的深拷贝进阶版本 赋值运算符重载的深拷贝进阶 总结 上期我们学习了C中深拷贝的传统版本,今天我们将学习更为高效的版本。 拷贝构造函数的深拷贝进阶版本 传统版本代码如下: string(string& s):_str(new char[strlen(s._str)…...

导行电磁波从纵向场分量求其他方向分量的矩阵表示

导行电磁波从纵向场分量求解其他方向分量的矩阵表示 导行电磁波传播的特点 电磁波在均匀、线性、各向同性的空间中沿着 z z z轴传播,可用分离变量法将时间轴、 z z z轴与 x , y x,y x,y轴分离,电磁波的形式可表示为: E ⃗ E ⃗ ( x , y )…...

融资项目——swagger2的注解

1. ApiModel与ApiModelProperty(在实体类中使用) 如上图,ApiModel加在实体类上方,用于整体描述实体类。ApiModelProperty(value"xxx",example"xxx")放于每个属性上方,用于对属性进行描述。swagger2网页上的效果如下图&am…...

【性能优化】MySql数据库查询优化方案

阅读本文你的收获 了解系统运行效率提升的整体解决思路和方向学会MySQl中进行数据库查询优化的步骤学会看慢查询、执行计划、进行性能分析、调优 一、问题:如果你的系统运行很慢,你有什么解决方案? ​关于这个问题,我们通常首先…...

Chrome浏览器http自动跳https问题

现象: Chrome浏览器访问http页面时有时会自动跳转https,导致一些问题。比如: 开发阶段访问dev环境网址跳https,后端还是http,导致接口跨域。 复现: 先访问http网址,再改成https访问&#xf…...

【C++进阶02】多态

一、多态的概念及定义 1.1 多态的概念 多态简单来说就是多种形态 同一个行为,不同对象去完成时 会产生出不同的状态 多态分为静态多态和动态多态 静态多态指的是编译时 在程序编译期间确定了程序的行为 比如:函数重载 动态多态指的是运行时 在程序运行…...

PHP开发日志——循环和条件语句嵌套不同,效率不同(循环内加入条件语句,条件语句判断后加入循环,array_map函数中加入条件语句)

十多年前开发框架时,为了效率不断试过各种代码写法,今天又遇到了,想想php8时代会不会有所变化,结果其实也还是和当年一样,但当年没写博客,但现在可以把数据记录下来了。 PHP_loop_ireflies_dark_forest 项目…...

【Seata源码学习 】 扫描@GlobalTransaction注解 篇一

1. SeataAutoConfiguration 自动配置类的加载 基于SpringBoot的starter机制,在应用上下文启动时,会加载SeataAutoConfiguration自动配置类 # Auto Configure org.springframework.boot.autoconfigure.EnableAutoConfigurationio.seata.spring.boot.aut…...

DBA-MySql面试问题及答案-上

文章目录 1.什么是数据库?2.如何查看某个操作的语法?3.MySql的存储引擎有哪些?4.常用的2种存储引擎?6.可以针对表设置引擎吗?如何设置?6.选择合适的存储引擎?7.选择合适的数据类型8.char & varchar9.Mysql字符集10.如何选择…...

网络爬虫之Ajax动态数据采集

动态数据采集 规则 有时候我们在用 requests 抓取页面的时候,得到的结果可能和在浏览器中看到的不一样,在浏览器中可以看到正常显示的页面教据,但是使用 requests 得到的结果并没有,这是因为requests 获取的都是原始的 HTML 文档…...

c语言的初始学习(练习)

##初学c语言---MOOC浙江大学翁恺先生学习c语言 那么我们先看看这个题目吧,这是初始语法的应用。 记住,我们的程序是按步骤执行的,并不是在不同的两行同时进行。 程序设计:1.了解题目的需要,几个变量需要用到&#x…...

研究论文 2022-Oncoimmunology:AI+癌RNA-seq数据 识别细胞景观

Wang, Xin, et al. "Deep learning using bulk RNA-seq data expands cell landscape identification in tumor microenvironment." Oncoimmunology 11.1 (2022): 2043662. https://www.tandfonline.com/doi/full/10.1080/2162402X.2022.2043662 被引次数&#xff1…...

ChatGPT4与ArcGIS Pro3助力AI 地理空间分析和可视化及助力科研论文写作

在地学领域,ArcGIS几乎成为了每位科研工作者作图、数据分析的必备工具,而ArcGIS Pro3除了良好地继承了ArcMap强大的数据管理、制图、空间分析等能力,还具有二三维融合、大数据、矢量切片制作及发布、任务工作流、时空立方体等特色功能&#x…...

okhttp系列-一些上限值

1.正在执行的任务数量最大值是64 异步请求放入readyAsyncCalls后,遍历readyAsyncCalls取出任务去执行的时候,如果发现runningAsyncCalls的数量大于等于64,就不从readyAsyncCalls取出任务执行。 public final class Dispatcher {private int …...

C++面向对象(OOP)编程-STL详解(vector)

本文主要介绍STL六大组件,并主要介绍一些容器的使用。 目录 1 泛型编程 2 CSTL 3 STL 六大组件 4 容器 4.1 顺序性容器 4.1.1 顺序性容器的使用场景 4.2 关联式容器 4.2.1 关联式容器的使用场景 4.3 容器适配器 4.3.1 容器适配器的使用场景 5 具体容器的…...

postman几种常见的请求方式

1、get请求直接拼URL形式 对于http接口,有get和post两种请求方式,当接口说明中未明确post中入参必须是json串时,均可用url方式请求 参数既可以写到URL中,也可写到参数列表中,都一样,请求时候都是拼URL 2&am…...

openai最新探索:超级对齐是否可行?

前言 今天来介绍一篇openai最新的paper:弱到强的对齐。 openai专门成立了一个团队来做大模型的超级对齐即superhuman model,之前chatgpt取得成功依赖RLHF即依赖人类反馈,但是作者期望的superhuman model将会是一个能够处理各种复杂问题的强…...

本地websocket服务端结合cpolar内网穿透实现公网访问

文章目录 1. Java 服务端demo环境2. 在pom文件引入第三包封装的netty框架maven坐标3. 创建服务端,以接口模式调用,方便外部调用4. 启动服务,出现以下信息表示启动成功,暴露端口默认99995. 创建隧道映射内网端口6. 查看状态->在线隧道,复制所创建隧道的公网地址加端口号7. 以…...

关于“Python”的核心知识点整理大全37

目录 13.6.2 响应外星人和飞船碰撞 game_stats.py settings.py alien_invasion.py game_functions.py ship.py 注意 13.6.3 有外星人到达屏幕底端 game_functions.py 13.6.4 游戏结束 game_stats.py game_functions.py 13.7 确定应运行游戏的哪些部分 alien_inva…...

Vivado中的FFT IP核使用(含代码)

本文介绍了Vidado中FFT IP核的使用,具体内容为:调用IP核>>配置界面介绍>>IP核端口介绍>>MATLAB生成测试数据>>测试verilogHDL>>TestBench仿真>>结果验证>>FFT运算。 1、调用IP核 该IP核对应手册pg109_xfft.pd…...

VTK如何让部分单位不可见

最近遇到一个需求&#xff0c;需要让一个vtkDataSet中的部分单元不可见&#xff0c;查阅了一些资料大概有以下几种方式 1.通过颜色映射表来进行&#xff0c;是最正规的做法 vtkNew<vtkLookupTable> lut; //值为0不显示&#xff0c;主要是最后一个参数&#xff0c;透明度…...

Axios请求超时重发机制

Axios 超时重新请求实现方案 在 Axios 中实现超时重新请求可以通过以下几种方式&#xff1a; 1. 使用拦截器实现自动重试 import axios from axios;// 创建axios实例 const instance axios.create();// 设置超时时间 instance.defaults.timeout 5000;// 最大重试次数 cons…...

NFT模式:数字资产确权与链游经济系统构建

NFT模式&#xff1a;数字资产确权与链游经济系统构建 ——从技术架构到可持续生态的范式革命 一、确权技术革新&#xff1a;构建可信数字资产基石 1. 区块链底层架构的进化 跨链互操作协议&#xff1a;基于LayerZero协议实现以太坊、Solana等公链资产互通&#xff0c;通过零知…...

使用Matplotlib创建炫酷的3D散点图:数据可视化的新维度

文章目录 基础实现代码代码解析进阶技巧1. 自定义点的大小和颜色2. 添加图例和样式美化3. 真实数据应用示例实用技巧与注意事项完整示例(带样式)应用场景在数据科学和可视化领域,三维图形能为我们提供更丰富的数据洞察。本文将手把手教你如何使用Python的Matplotlib库创建引…...

【Go语言基础【13】】函数、闭包、方法

文章目录 零、概述一、函数基础1、函数基础概念2、参数传递机制3、返回值特性3.1. 多返回值3.2. 命名返回值3.3. 错误处理 二、函数类型与高阶函数1. 函数类型定义2. 高阶函数&#xff08;函数作为参数、返回值&#xff09; 三、匿名函数与闭包1. 匿名函数&#xff08;Lambda函…...

【C++进阶篇】智能指针

C内存管理终极指南&#xff1a;智能指针从入门到源码剖析 一. 智能指针1.1 auto_ptr1.2 unique_ptr1.3 shared_ptr1.4 make_shared 二. 原理三. shared_ptr循环引用问题三. 线程安全问题四. 内存泄漏4.1 什么是内存泄漏4.2 危害4.3 避免内存泄漏 五. 最后 一. 智能指针 智能指…...

【学习笔记】erase 删除顺序迭代器后迭代器失效的解决方案

目录 使用 erase 返回值继续迭代使用索引进行遍历 我们知道类似 vector 的顺序迭代器被删除后&#xff0c;迭代器会失效&#xff0c;因为顺序迭代器在内存中是连续存储的&#xff0c;元素删除后&#xff0c;后续元素会前移。 但一些场景中&#xff0c;我们又需要在执行删除操作…...

python爬虫——气象数据爬取

一、导入库与全局配置 python 运行 import json import datetime import time import requests from sqlalchemy import create_engine import csv import pandas as pd作用&#xff1a; 引入数据解析、网络请求、时间处理、数据库操作等所需库。requests&#xff1a;发送 …...

django blank 与 null的区别

1.blank blank控制表单验证时是否允许字段为空 2.null null控制数据库层面是否为空 但是&#xff0c;要注意以下几点&#xff1a; Django的表单验证与null无关&#xff1a;null参数控制的是数据库层面字段是否可以为NULL&#xff0c;而blank参数控制的是Django表单验证时字…...

QT开发技术【ffmpeg + QAudioOutput】音乐播放器

一、 介绍 使用ffmpeg 4.2.2 在数字化浪潮席卷全球的当下&#xff0c;音视频内容犹如璀璨繁星&#xff0c;点亮了人们的生活与工作。从短视频平台上令人捧腹的搞笑视频&#xff0c;到在线课堂中知识渊博的专家授课&#xff0c;再到影视平台上扣人心弦的高清大片&#xff0c;音…...