模拟string(四)详解

目录

  • 判断string大小关系
    • bool operator==(const string&s1,const string s2)
      • 代码
    • bool operator<(const string& s1, const string& s2)
      • 代码
    • bool operator<=(const string& s1, const string& s2)
      • 代码
    • bool operator>(const string& s1, const string& s2)
      • 代码
    • bool operator>=(const string& s1, const string& s2)
      • 代码
    • bool operator!=(const string& s1, const string& s2)
      • 代码
  • void clear()清除数据
    • 代码
  • ostream& operator<<(ostream& out, const string& s)实现string的流插入
    • 代码
  • istream& operator>>(istream& in, string& s)实现string的流提取
    • 代码
  • istream& getline(istream& in, string& s)获取输入的一行
    • 代码
  • string(const string& s)拷贝构造现代写法
    • 传统写法
    • 代码
    • 代码
  • 总结
  • 拓展1
  • 拓展2
    • 引用技术

感谢各位大佬对我的支持,如果我的文章对你有用,欢迎点击以下链接
🐒🐒🐒 个人主页
🥸🥸🥸 C语言
🐿️🐿️🐿️ C语言例题
🐣🐣🐣 python
🐓🐓🐓 数据结构C语言
🐔🐔🐔 C++
🐿️🐿️🐿️ 文章链接目录

判断string大小关系

bool operator==(const string&s1,const string s2)

代码

bool operator==(const string& s1, const string& s2){int ret = strcmp(s1.c_str(), s2.c_str());return ret == 0;}

bool operator<(const string& s1, const string& s2)

代码

	bool operator<(const string& s1, const string& s2){int ret = strcmp(s1.c_str(), s2.c_str());return ret < 0;}

bool operator<=(const string& s1, const string& s2)

代码

bool operator<=(const string& s1, const string& s2){return s1 < s2 || s1 == s2;}

bool operator>(const string& s1, const string& s2)

代码

bool operator>(const string& s1, const string& s2){return !(s1 <= s2);}

bool operator>=(const string& s1, const string& s2)

代码

bool operator>=(const string& s1, const string& s2){return !(s1 < s2);}

bool operator!=(const string& s1, const string& s2)

代码

bool operator!=(const string& s1, const string& s2){return !(s1 == s2);}

void clear()清除数据

代码

	void clear(){_size = 0;_str[_size] = '\0';
}

ostream& operator<<(ostream& out, const string& s)实现string的流插入

代码

ostream& operator<<(ostream& out, const string& s){for (auto ch : s){out << ch;}return out;}

istream& operator>>(istream& in, string& s)实现string的流提取

代码

istream& operator>>(istream& in, string& s){s.clear();char ch;ch = in.get();char buff[128];size_t i = 0;while (ch != ' ' && ch != '\n'){buff[i++] = ch;if (i == 127){buff[127] = '\0';s += buff;i = 0;}ch = in.get();}if (i > 0){buff[i] = '\0';s += buff;}return in;}

in.get()是遇到什么字符就直接取,因为有时候我们想要得到空格字符,但是用其他的输入会将空格视为结束
注意这里的string& s还没有开辟空间,所以ch = in.get()不能写成s[i]这样的形式

istream& getline(istream& in, string& s)获取输入的一行

代码

istream& getline(istream& in, string& s){s.clear();char ch;ch = in.get();char buff[128];size_t i = 0;while (ch != '\n'){buff[i++] = ch;if (i == 127){buff[127] = '\0';s += buff;i = 0;}ch = in.get();}if (i > 0){buff[i] = '\0';s += buff;}return in;}

string(const string& s)拷贝构造现代写法

拷贝构造的传统写法就是先开辟一块同样大小的空间,然后将数据拷贝到那块空间里

传统写法

        string(const string& s){_str = new char[s._capacity + 1];strcpy(_str, s._str);_size = s._size;_capacity = s._capacity;}

添加图片注释,不超过 140 字(可选)

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

代码

//现代写法
string(const string& s)
{string tmp(s._str);swap(tmp);
}

这个写法的过程如下图,首先this指针是表示的s2,s2会先指向空(不指向空会出现一些问题)

添加图片注释,不超过 140 字(可选)

然后进入函数后string tmp(s._str)会调用下面这个构造函数

string(const char* str = ""):_size(strlen(str)){_capacity = _size;_str = new char[_capacity + 1];strcpy(_str, str);}

所以tmp会拷贝s1的数据

添加图片注释,不超过 140 字(可选)

然后swap(tmp)就是让s2和tmp进行交换,因为this指针是s2
原因是string(const string& s)这个拷贝构造函数中的this指针就是s2,所以函数里面的this指针也默认是s2,交换后因为s2一开始就是指向的空,所以交换后tmp也指向空,而s2就指向tmp开出来的新空间

添加图片注释,不超过 140 字(可选)

因为tmp是一个局部对象,出了作用域后就会调用析构函数销毁
现在回到之前的问题为什么s2最开始是指向空的
因为如果s2不指向空,那么s2就是一个随机值,当s2和tmp交换后,tmp就指向一个随机值,tmp调用析构函数后会delete他的_str,但是tmp是一个随机值,delete一个随机值就会出现问题

string& operator=(const string& s)现代写法
现在需要将s3的值赋值给s1,注意赋值是两个已经存在的对象,所以他们的空间是已经开辟好了的
如果我们想直接将s3拷贝给s1的话需要分情况

添加图片注释,不超过 140 字(可选)

第一种情况就是s3的size大于s1的capacity,这样s1就需要扩容
第二种情况就是s3的size小于s1的capacity,但是如果s1的capacity远大于s1,比如capacity=1000,size=1
在实际当中一般不会这样拷贝数据,而是重新开一块新的空间,然后拷贝s3的数据,之后让s1指向新开的空间,然后释放s1之前的空间

添加图片注释,不超过 140 字(可选)

添加图片注释,不超过 140 字(可选)

添加图片注释,不超过 140 字(可选)

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

这是上面的传统写法
现代写法过程如下,先创造一个对象s2拷贝s3的数据

添加图片注释,不超过 140 字(可选)

然后s1和s2交换,交换完之后因为s2是局部对象,出了作用域后会调用析构函数,所以s1之前的空间会被释放掉

添加图片注释,不超过 140 字(可选)

代码

//简化版
string& operator=(string& s2)
{swap(s2);return *this;
}

这个函数和第一个函数的区别是
第一个函数的传引用,所以s就是s3的别名,然后通过s3拷贝构造出s2,再将s2和s1进行交换
第二个函数是传值传参,传值传参会调用拷贝构造函数(形参是实参的拷贝)(这里要和之前的拷贝构造死循环问题要区分开,两个是不一样的),然后s2和s1进行交换

总结

现代写法相对于传统写法在二插树 链表等场景优势比较明显
因为树的节点如果用传统写法需要一个节点一个节点的开空间,然后再释放,而现代写法就是直接调用拷贝构造函数,然后就交换,并且省了自己去释放空间

拓展1

现在string这个类中的成员变量有下面这几个

添加图片注释,不超过 140 字(可选)

我们假设现在的环境是32位,现在需要计算他的sizeof()的大小
32位环境下指针的大小是4个字节,size_t的大小是4个字节,所以根据内存对齐规则,他的大小是12个字节,对于static修饰的变量不算进类里面,因为类里面的静态成员变量存的地方是在静态区里的,这个变量的生命周期是全局的,也就是我们可以把npos看成在类外面定义的全局变量

int main()
{std::string s1("11111");cout << sizeof(s1) << endl;jack::string s2("11111");cout << sizeof(s2) << endl;return 0;
}

添加图片注释,不超过 140 字(可选)

上面代码中我们用了两个不同的string,一个是库里的string,另一个是我们自己写的string,我们自己写的大小是12,而库里的string却是28
下面我们来讲解一下为什么库里的string是28
通过调试我们可以看到s1多了原始视图

添加图片注释,不超过 140 字(可选)

添加图片注释,不超过 140 字(可选)

这里的_Mysize和_Myres其实就是上面的size和capacity
那_Bx又是什么呢

_Bx点开后有三个部分_Buf ,_Ptr, _Alias(其实只有两个部分,编译器做了一下优化所以就有三个部分了)
我们再点开_Buf

添加图片注释,不超过 140 字(可选)

发现这个_Buf存的是字符,这些字符正好是我们输入
所以我们可以推断出这个_Buf可能就是多出来的那部分空间,因为_Buf是一个字符数组,里面有16个元素,他的大小就是16个字节,那么16+12正好就是28

也就是说我们定义的成员变量里面是有一个_Buf数组的,只是我们看不到而已

添加图片注释,不超过 140 字(可选)

那这个数组是固定大小的吗
其实当_size<16的时候数据就存在_Buf里面(_size不能等于16,因为需要留一个位置存放\0),我们来验证一下
这次的s1字符串里面有15个字符

添加图片注释,不超过 140 字(可选)

当变成16个字符的时候这个_Buf里面就没有字符了,因为装不下

在这里插入图片描述

那会存在哪呢?
_Ptr是一个指针,他会指向一块空间,而这块空间就是存放数据的地方
在这里插入图片描述

注意不同的编译器情况是不一样的,这是VS的环境下运行的,这种方法就是空间换时间,当_size<16的时候就不需要在堆上开空间了,而是在对象里面开空间,对象里面开的空间是在栈上的,因为栈上开空间要比堆上开更快,所以才这样搞

拓展2

在之前深拷贝的时候我们都需要先开一块同样大小的空间,然后拷贝数据

在这里插入图片描述

那我们能不能就让他们指向同一块空间,这样就省了开空间了

在这里插入图片描述

这样做有两个问题:第一个问题是会多次析构,第二个问题是其中一个修改会影响另一个

引用技术

为了解决这个问题我们需要用到一个引用技术
在了解到这个方法的时候我第一反应想到的是之前学过的一种做题方法,我们需要将arr1各个数字出现的次数统计出来

在这里插入图片描述

这个方法会需要有一个arr2的数组来记录,arr2的下标就对应arr1元素的值,arr2的下标对应的元素就是arr1元素出现的次数
就上面这个例子
0一共就在arr1里出现了1次,所以我们arr2[0]++(这里arr2中的所以元素初始化为0),
1一共出现了三次,所以arr2[1]++
2一共出现了1次,所以arr2[2]++

就这样遍历一遍arr1后就可以得到他每个数字出现的次数了

在这里插入图片描述

引用技术和这个比较类似
就是统计指向这块空间的对象有多少个,每增加一个对象就让计数的数字加1
在这里插入图片描述

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

当有对象要析构的时候就先让计数的数字减1

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

当计数的数字为1时表示这块空间只属于他自己,那么就可以放心的析构了

在这里插入图片描述

只不过这个方法只解决了第一个问题,第二个问题还是解决不了,所以当要修改的时候我们需要检查一下记录的数字,如果为1就直接修改,如果大于1就先拷贝再修改,然后数字减1

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

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

相关文章

Stable Diffusion WebUI本地环境搭建

一、项目代码下载 git clone https://github.com/AUTOMATIC1111/stable-diffusion-webui 二、环境配置 conda create --n stafu python3.10.6 实际上跟自己创建的环境没有关系&#xff0c;项目启动会自动复制这个环境&#xff0c;之后项目根据这个基础环境构建 也可以在自己…

机器学习——第一章 绪论

目录 1. 1 引言 1. 2 基本术语 1.3 假设空间 1.4 归纳偏好 1. 1 引言 机器学习致力于研究如何通过计算的手段&#xff0c;利用经验来玫善系统自身的性能在计算机系统中&#xff0c;"经验"通常以"数据"形式存在&#xff0c;因此&#xff0c;机器学习所研…

由字节对齐引发的一场“血案“

最近在搞个网络通信协议&#xff0c; 采用socket udp传输&#xff0c; 运行时&#xff0c;居然报段错误了&#xff0c; 经过debug&#xff0c;发现居然是因为字节对齐问题导致的。 这个问题在实现通信协议&#xff0c;是经常会遇到的问题&#xff0c; 为了方便读者理解&am…

PSVR2下个月将正式支持PC

PlayStation VR 2将于下个月正式支持PC平台。连接PC&#xff0c;需要使用PlayStation VR2头显PC适配器&#xff0c;该适配器将于8月7日发售。 需要注意的是&#xff0c;玩家还需要一根兼容DisplayPort 1.4的线缆、一个Steam账号以及满足最低配置要求的PC。 索尼特别强调&#…

js 替换json中的转义字符 \

例如有以下字符串 "\"{\\\"account\\\":\\\"66\\\",\\\"name\\\":\\\"66\\\"}\"" 想得到如下字符串 {"account":"66","name":"66"} 执行替换字符串 "\"{…

大坝安全监测设备有哪些主要功能?

推荐型号&#xff1a;TH-WY1】大坝安全监测设备的主要功能包括以下几个方面&#xff1a; 1. **实时监测大坝的各项物理参数**&#xff1a;包括应变、位移、水位、流量等<sup>1</sup><sup>2</sup>。 2. **数据处理和分析**&#xff1a;对监测数据进行处…

热门音效、BGM哪里可以免费下载?

剪辑的奇妙世界等你探索&#xff01;在这个创意的领域里&#xff0c;音效是创造氛围、增强表现力的重要元素。我整理了8个优质的剪辑音效素材网站&#xff0c;它们提供了丰富多样的音效资源&#xff0c;无论是制作视频、音乐还是动画&#xff0c;都能为你提供所需的声音。 1、b…

单关节电机动力学辨识

这是一个单关节电机的动力学辨识过程&#xff0c;这是一个yaw轴转动电机的动力学辨识过程 1、动力学建模 &#xff08;1&#xff09;整体动力学 F J α f F J\alpha f FJαf 单关节的物理量包括惯性项、离心力和科氏力、摩擦力。这里忽略离心力和科氏力&#xff0c;据说…

信息学奥赛初赛天天练-47-CSP-J2020完善程序1-质数、因数、质因数、质因数分解算法、质因数分解算法优化

PDF文档公众号回复关键字:20240727 2020 CSP-J 完善程序1 1 完善程序 (单选题 &#xff0c;每小题3分&#xff0c;共30分) 质因数分解给出正整数 n&#xff0c;请输出将 n 质因数分解的结果&#xff0c;结果从小到大输出 例如&#xff1a;输入 n120&#xff0c;程序应该输出…

mysql报错:Unknown collation: ‘utf8mb4_0900_ai_ci‘的原因及解决方法

参考博客&#xff1a;http://t.csdnimg.cn/NRzyk 报错场景描述 使用navicate在查询中运行sql语句时报错&#xff1a;Unknown collation: utf8mb4_0900_ai_ci 报错原因 生成转储文件的数据库版本为8.0&#xff0c;我本地数据库版本为5.6&#xff0c;高版本导入到低版本&…

【C++】透析类和对象(下)

有不懂的可以翻阅我之前文章&#xff01; 个人主页&#xff1a;CSDN_小八哥向前冲 所属专栏&#xff1a;CSDN_C入门 目录 拷贝构造函数 运算符重载 赋值运算符重载 取地址运算符重载 const成员函数 取地址重载 再探构造函数 初始化列表 类型转换 static成员 友元 内…

【CN】Argo 持续集成和交付(一)

1.简介 Argo 英 [ˈɑ:ɡəu] 美 [ˈɑrˌɡo] Kubernetes 原生工具&#xff0c;用于运行工作流程、管理集群以及正确执行 GitOps。 Argo 于 2020 年 3 月 26 日被 CNCF 接受为孵化成熟度级别&#xff0c;然后于 2022 年 12 月 6 日转移到毕业成熟度级别。 argoproj.github.i…

(最全最小白易懂版)Yolov8新手教程-配置环境、数据集处理、目标检测、结果分析处理(图像指标、可视化结果)、报错分析等全过程学习记录

目录 一、安装环境&#xff08;配置yolo、demo测试&#xff09; 二、数据集准备&#xff08;格式学习&#xff09; 三、训练数据集 1.划分数据集 2.训练数据集 2.1常规训练 2.2微调 3.各种报错记录 3.1AttributeError 3.2TypeError 3.3Error while loading conda en…

Flutter Dio网络请求报错FormatException: Unexpected character

最近开发Flutter项目&#xff0c;网络请求采用的是Dio框架&#xff0c;在发起网络请求的时候报错&#xff1a; 网络请求返回的数据为&#xff1a; var returnCitySN {\"cip\": \"127.0.0.1\", \"cid\": \"00\", \"cname\"…

浅谈 JVM 的内存划分、类加载、垃圾回收机制

文章目录 一、JVM内存划分1.1、JVM为什么要进行内存划分&#xff1f; 二、JVM类加载2.1、什么是类加载&#xff1f;2.2、类加载大体过程2.3、何时触发类加载&#xff1f;2.4、双亲委派模型[!面试高频问题]2.4.1、类加载器2.4.1、什么是双亲委派模型&#xff1f; 三、JVM 垃圾回…

Flink SQL 的工作机制

前言 Flink SQL 引擎的工作流总结如图所示。 从图中可以看出&#xff0c;一段查询 SQL / 使用TableAPI 编写的程序&#xff08;以下简称 TableAPI 代码&#xff09;从输入到编译为可执行的 JobGraph 主要经历如下几个阶段&#xff1a; 将 SQL文本 / TableAPI 代码转化为逻辑执…

书生大模型实战营--L1关卡-OpenCompass 评测 InternLM-1.8B 实践

一、使用 OpenCompass 评测 internlm2-chat-1.8b 模型在 MMLU 数据集上的性能 1、使用lmdeploy部署 internlm2-chat-1.8b模型 2、根据OpenCompass官网教程安装并下载数据集 opencompass/README_zh-CN.md at main open-compass/opencompass GitHub 注意&#xff1a; pyhton…

【Java】this关键字、构造方法、标准javabean类(009)

目录 ♦️构造方法 &#x1f383;无参数构造方法&#xff08;空参构造&#xff09; &#x1f383;有参数构造方法 ♦️this关键字 &#x1f383;就近原则 &#x1f383;使用this关键字调用本类中的属性 ​编辑 &#x1f383;使用this关键字调用成员方法 ​编辑 &#x…

Collention集合基础知识

Array 数组是一种连续的内存空间存储相同数据类型数据的线性数据结构 数组获取其他元素的地址值 寻址公式 a[i] baseaddress i*datatypesize 为什么数组索引从0开始 从1开始不行吗 从0开始寻址公式 a[i] baseaddress i*datatypesize 从1开始寻址公式 a[i] baseadd…

【计算机网络】无线网络和移动网络(第9章)大纲(共70+页)

最后只复习了1.5天&#xff0c;应用层简单过了一遍。 本来是mindmap的&#xff0c;但是太大了只能导出成提纲了&#xff0c;凑合看吧orz。 如果你找我要源文件&#xff0c;最好是在2024年&#xff0c;不然我可能就找不到了&#xff08;&#xff09;。