C++STL初阶(3):string模拟实现的完善

1.流提取>>的优化(利用缓存区的思想)

istream& operator>>(istream& is,string& str) {str.clear();char c;c = is.get();while (c != '\0' && c != '\n') {str += c;c = is.get();}return is;
}

        在上文的对string的实践中,对于>>的重载(如上代码),当我们需要输入很多文字的时候,因为每次都会利用一次push_back(+=的实现是对push_back的复用),扩容相对较频繁。需要经历很多次扩容,开销较大。

解决办法1:通过reserve函数提前对str的空间进行规划 

           

        但是这样的reserve只对预计空间在100左右的string凑效。当要输入的字符很多时,依然需要多次扩容。

解决办法2:buff数组(利用缓冲区的思想):

先将输入的内容都放入buff数组中。

   加入并使用一个人为确定大小的buff数组,既避免了频繁扩容,也避免了一次性扩太多造成浪费。每次几乎都不会执行push_back,都是按照需要开的。

这是一种借助缓冲区的思路,每次都将即将输入的单个字符放在缓冲区。在有必要时,将缓冲区的内容一次性全部放进_str中以提升效率。

每当一次输入结束(输入了'\n'或者‘ ’) ,就从buff数组中全部拿出来并且通过append放入_str中,因此只会根据大小扩容一次。

必须有将buff数组的最后一个元素赋\0的操作,因为insert的逻辑是会覆盖掉原数组的\0的。

istream& operator>>(istream& is,string& str) {str.clear();char buff[128]; int i = 0;char c;c = is.get();while (c != '\0' && c != '\n') {buff[i++] = c;//0 - 126用来放char。由于insert的底层逻辑会覆盖\0,所以我们要在buff的末尾加\0if (i == 127) {buff[i] = '\0';str += buff;i = 0;}//str += c;c = is.get();}if (i != 0) {buff[i] = '\0';str += buff;}


2.拷贝构造与赋值运算符的现代写法

对于拷贝构造和赋值运算符重载,还有一种“现代写法”

先复习一下传统写法:

string::string(string& s) {_str = new char[s._size+1];//留一个位置给\0strcpy(_str, s._str);_size = s. _size;_capacity = s._capacity;
}

       传统思路基本都是根据传入的string引用开一个相应的空间,然后将_size和_capacity一个一个赋值。 

而现代写法的核心思路就是“让别人干活” :

       我们使用传入参数s的_str进行构造一个新的字符串tmp。接着将tmp的三项数据拷贝交换给this

                             

                             

当然,在string环境下的现代写法与传统写法没有特别大的优势,这是因为string的字符串的拷贝没有什么代价。 

还可以复用之前写的swap。

        比如上图,要将s1赋值拷贝给s2,也就是先通过构造tmp来获得一份s1的拷贝,然后将这份拷贝的内容交换。其本质是this不能显示调用构造函数。 

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

赋值运算符:

同样先观察原来的实现方法:

string& string::operator=(const string& s) {if (this != &s) {char* tmp = new char[s._size + 1];//留一个位置给\0strcpy(tmp,s._str);_size = s._size;_capacity = s._capacity;delete[] _str;_str = tmp;tmp = nullptr;}return *this;
}

依然先通过一个tmp来构造一个与s3一样一样的string,然后通过swap将tmp的内容与s1交换即可。 

string& string::operator=(const string& s) {if (this != &s) {string tmp(s._str);swap(tmp);}return *this;
}

swap的前面没有写作用域,在内部函数没有写前面的作用域就是对this进行该操作。

                       

由于tmp是临时变量,并且tmp指向了s1原来指向的"hello world\0",所以在出栈帧之后tmp会被销毁,而销毁又会调用析构函数。所以hello world所在的string就自动无了。

还可以优化成:

                

本质是利用传值传参的拷贝,不过这种方法记得改一改头文件中的参数类型。


3.写时拷贝(了解即可)

当我们对对象进行拷贝时不需要对对象进行修改时:

为了避免深拷贝对时间的浪费,我们能不能就利用浅拷贝呢?

目前已知的浅拷贝有两个如下问题:

                                                 

引用计数解决问题1:引入一个计数的整形变量,每次拷贝时都会将这个整形变量++,每析构一次一次将这个变量--  ; 每次最后一个析构的对象才释放空间,否则只是将对应的使用次数--

写时拷贝解决问题2:如果有需要改变原数组的需求时:还是按照原来的进行拷贝,但是只对“对原对象进行了写入和修改”的对象进行拷贝。因此,所有的写入函数,如:insert append erase push_back等都需要重新加一个函数:

copy_on_write:

而对于copy_on_write的内部:通过对引用计数的判断来决定是否需要深拷贝。

                      

因此,写时拷贝的目的是让不会改变原_str内容的对象共用一个_str,需要改变的还是会进行深拷贝。所以,只要不修改原_str,这样的拷贝方式稳赚不赔。

写时拷贝就是一种拖延症,是在浅拷贝的基础之上增加了引用计数的方式来实现的。

C++面试中string类的一种正确写法 | 酷 壳 - CoolShell 

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Android Lottie 体积优化实践:从 6.4 MB 降到 530 KB

一、说明 产品提出需求:用户有 8 个等级,每个等级对应一个奖牌动画。 按照常用的实现方式: 设计提供 8 个 lottie 动画(8 个 json 文件)。研发将 json 文件打包进入 APK 中。根据不同等级播放指定的动画。 每一个 …

React + SpringBoot实现图片预览和视频在线播放,其中视频实现切片保存和分段播放

图片预览和视频在线播放 需求描述 实现播放视频的需求时,往往是前端直接加载一个mp4文件,这样做法在遇到视频文件较大时,容易造成卡顿,不能及时加载出来。我们可以将视频进行切片,然后分段加载。播放一点加载一点&am…

Nginx(openresty) 查看连接数和并发送

1 通过浏览器查看 #修改nginx配置文件 location /status {stub_status on;access_log off;allow 192.168.50.0/24;deny all;} #重新加载 sudo /usr/local/openresty/nginx/sbin/nginx -s reloadActive connections //当前 Nginx 当前处理的活动连接数。 server accepts handl…

【kubernetes】k8s集群中的ingress(对外服务)规则详解

目录 一、Ingress 简介 1.1service的作用 1.2外部访问方案 (四种)🌹🌹🌹 部署externalIPs 1.3Ingress 是什么 二、Ingress 组成🌹🌹🌹 三、Ingress 工作原理🐱&#x1f…

kafka的leader和follower

leader和follower kafka的leader和follower是相对于分区有意义的,不是相对于broker。 因为每个分区都有leader和follower, leader负责读写数据。 follower负责复制leader的数据保存到自己的日志数据中,并在leader挂掉后重新选举出leader。 kafka会再…

九家大模型“决战”高考!AI作文哪家强?阅卷名师点评来了!

2024.06.07 本文字数:12474,阅读时长大约21分钟 导读:语文老师对AI作文的评价是,“中规中矩,没有‘血肉’,缺一点情感和灵气。” 作者 | 第一财经 刘晓洁 冯小芯 马一凡 吕倩 又到一年高考季,…

使用树莓派和 L298N 来 DIY 小车底盘

树莓派小车可以作为 STEM(科学、技术、工程、数学)教育的工具,在实际操作中帮助学生理解和学习电子技术、编程和机器人原理。可以培养学生的动手能力、解决问题的能力和创新思维。 随着近年 AI 技术的高速发展,SLAM、VSLAM 甚至带…

[office] Excel教学:Excel通配符怎么用? #其他#职场发展

Excel教学:Excel通配符怎么用? 尽管Excel使用了很多年,但很多人都还是忽略了Excel通配符的存在,不知道通配符是什么,不知道如何使用它。今天我就完整地介绍一下通配符,让你彻底地认识通配符。 关于通配符…

结构体(1)<C语言>

导言 结构体是C语言中的一种自定义类型,它的值(成员变量)可以是多个,且这些值可以为不同类型,这也是和数组的主要区别,下面将介绍它的一些基本用法,包括:结构体的创建、结构体变量的…

MySQL基础_10.约束

文章目录 第一章、约束1.1 约束的定义1.2 非空约束1.3 唯一性约束1.4 主键约束1.5 自增列1.6 外键约束1.7 CHECK约束1.8 DEFAULT约束 第一章、约束 1.1 约束的定义 约束是对表中字段的限制。 约束按照作用范围可以分为:列级约束和表级约束 列级约束:声…

VMware ESXi 8.0U2c macOS Unlocker OEM BIOS 集成网卡驱动 Marvell AQC 网卡定制版

VMware ESXi 8.0U2c macOS Unlocker & OEM BIOS 集成网卡驱动 Marvell AQC 网卡定制版 VMware ESXi 8.0U2c macOS Unlocker & OEM BIOS 集成网卡驱动和 NVMe 驱动 (集成驱动版) 发布 ESXi 8.0U2 集成驱动版,在个人电脑上运行企业级工作负载 请访问原文链…

基于SpringBoot+Vue旅游民宿信息管理系统设计和实现(源码+LW+调试文档+讲解等)

💗博主介绍:✌全网粉丝1W,CSDN作者、博客专家、全栈领域优质创作者,博客之星、平台优质作者、专注于Java、小程序技术领域和毕业项目实战✌💗 🌟文末获取源码数据库🌟 感兴趣的可以先收藏起来,还…

计算机SCI期刊,中科院2区,IF=6.9,收稿范围非常广泛

一、期刊名称 Journal of King Saud University—Computer and Information Sciences 二、期刊简介概况 期刊类型:SCI 学科领域:计算机科学 影响因子:6.9 中科院分区:2区 三、期刊征稿范围 《沙特国王大学计算机与信息科学杂…

电脑提示msvcp140.dll丢失的解决方法(附带详细msvcp140.dll文件分析)

msvcp140.dll是一个动态链接库(DLL)文件,属于Microsoft Visual C 2015 Redistributable的一部分。它全称为 "Microsoft C Runtime Library" 或 "Microsoft C Runtime Library",表明该文件是微软C运行时库的一…

【数据可视化系列】使用Python和Seaborn绘制相关性热力图

热力图(Heatmap)是一种数据可视化工具,它通过使用颜色的深浅来展示数据矩阵中数值的大小或密度。在热力图中,每种颜色的深浅代表数据的一个特定值或值的范围,通常使用红色、黄色和绿色等颜色渐变来表示数据的热度&…

《数字电路》

问答题4*5 在数字电路中,三极管经常工作在哪两种开关状态? 在数字电路中,三极管经常工作在饱和导通状态和截止状态。 时序电路根据输出信号分为哪两类? 时序电路根据输出信号分为莫尔型和米里型两类。 写出三种以上常用的二-十…

JVM学习-监控工具(三)

jconsole 从Java5开始,在JDK中自带的java监控和管理控制台用于对JVM中内存、线程、和类等的监控,是一个基本JMX(java management extendsions)的GUI性能监控工具 三种连接方式 Local:使用JConsole连接是一个正在本地系统运行的JVM&#xf…

XR和Steam VR项目合并问题

最近有一个项目是用Steam VR开发的,里面部分场景是用VRTK框架做的,还有一部分是用SteamVR SDK自带的Player预制直接开发的。 这样本身没有问题,因为最终都是通过SteamVR SDK处理的,VRTK也管理好了SteamVR的逻辑,并且支…

JVM学习-内存泄漏

内存泄漏的理解和分类 可达性分析算法来判断对象是否是不再使用的对象,本质都是判断一上对象是否还被引用,对于这种情况下,由于代码的实现不同就会出现很多内存泄漏问题(让JVM误以为此对象还在引用,无法回收,造成内存泄…

Redis 内存回收

文章目录 1. 过期key处理1.1 惰性删除1.2 周期删除 2. 内存淘汰策略 Redis 中数据过期策略采用定期删除惰性删除策略结合起来,以及采用淘汰策略来兜底。 定期删除策略:Redis 启用一个定时器定时监视所有的 key,判断key是否过期,过…