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.mzph.cn/web/24716.shtml

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

相关文章

blazehttp下载安装和自动化测试防护效果

blazehttp下载安装和自动化测试防护效果 说明测试环境的准备网站和waf配置blazehttp下载安装和测试测试效果waf安全日志查看 说明 需要docker环境和1panel面板 本测试使用blazehttp南墙waf进行测试,有兴趣的同学推荐使用雷池waf 测试环境的准备 使用1panel面板&am…

为什么会有虚像

本来我就打算写虚像相关的内容,实际上我看不懂光学的内容,我只是发觉书上没有使用变分法来做,而只是解析几何的变换,这个做法完全脱离实际,物理书为什么会这样写不知道原因,但是很明显这样的内容也非常的复…

docker基础,docker安装mysql,docker安装Nginx,docker安装mq,docker基础命令

核心功能操作镜像 Docker安装mysql docker run -d --name mysql -p 3306:3306 -e TZAsia/Shanghai -e MYSQL_ROOT_PASSWORDlcl15604007179 mysql docker的基本操作 docker rm 容器名称即可 docker ps 查看当前运行的容器 docker rm 干掉当前容器 docker logs 查看容器命令日…

瑞安面试分享

瑞安面试分享 面试时间:07/06/2024 方式:在线zoom,雇主会发面试链接,提前进入准备 瑞安招前端和后端开发,我面的是偏数据库设计的后端开发 问题1:自我介绍 寒暄后开始自我介绍,如果是后端就…

Golang:bytes 格式和解析数字字节值(10K、2M、3G等)

bytes 格式和解析数字字节值(10K、2M、3G等) 文档 https://github.com/labstack/gommon/tree/master/bytes 安装 go get github.com/labstack/gommon/bytes代码示例 格式化 bytes.Format(13231323) // 12.62MiB解析 b, _ : bytes.Parse("2M") // 2000000完整代…

代码随想录算法训练营Day32|122.买卖股票的最佳时机II、55.跳跃游戏、45.跳跃游戏II

买卖股票的最佳时机II 122. 买卖股票的最佳时机 II - 力扣(LeetCode) 这里我的贪心策略是,判断今天和前一天的股票差值,若差值大于0,则说明能获益,即卖出,每天都比较一次,将所有差…

为什么Vue的watch函数无法检测到父组件的参数变化?

在 Vue 中,watch 函数用于观察和响应 Vue 实例上的数据变动。然而,如果你在父组件中直接修改了数组或对象的内容(例如,通过索引直接设置一个项的值,或者使用 Array.prototype.push 修改数组),Vu…

【ARM Cache 及 MMU 系列文章 6 -- Cache 寄存器 CTR_EL0 | CLIDR | CCSIDR | CSSELR 使用详解 1】

请阅读【ARM Cache 及 MMU/MPU 系列文章专栏导读】 及【嵌入式开发学习必备专栏】 文章目录 Cache 常用寄存器Cache CSSELR 寄存器Cache CSSELR 使用场景Cache CSSELR 操作示例 Cache CLIDR 寄存器LoUU 介绍LoUU 使用 LoUIS 介绍CLIDR 使用 Cache CCSIDR 寄存器Cache CTR_EL0 C…

移动端投屏到大屏幕的操作详解

如果你懒得折腾电脑、电视或其他大屏设备上的影视软件安装及配置,可以选择直接在手机端上将影片投屏到电脑、电视或其他大屏设备上,这里给大家分享三种手机投屏的方法。 系统自带的投屏功能 不管是安卓、鸿蒙还是苹果操作系统,都自带了无线…

【RabbitMQ】exchange\channel\queue的联系

Exchange、Channel和Queue在RabbitMQ中各自扮演不同的角色,它们之间的联系构成了RabbitMQ消息传递的核心机制。以下是对它们之间联系的详细解释: Exchange(交换机): 交换机是RabbitMQ中的消息路由器,它接收…

8.3 Go 包的组织结构

💝💝💝欢迎莅临我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:「stormsha的主页」…

HTML静态网页成品作业(HTML+CSS)—— 家乡南宁介绍网页(2个页面)

🎉不定期分享源码,关注不丢失哦 文章目录 一、作品介绍二、作品演示三、代码目录四、网站代码HTML部分代码 五、源码获取 一、作品介绍 🏷️本套采用HTMLCSS,未使用Javacsript代码,共有2个页面。 二、作品演示 三、代…

使用`dbus-monitor`命令深入了解DBus通信

使用dbus-monitor命令深入了解DBus通信 DBus是一种消息总线系统,它允许应用程序在运行时进行通信。在Linux系统中,DBus是一个重要的组成部分,特别是在桌面环境中,如GNOME或KDE。dbus-monitor是一个命令行工具,用于监视…

【Python】解决Python报错:IndexError: list index out of range

​​​​ 文章目录 引言1. 错误详解2. 常见的出错场景2.1 循环中的索引错误2.2 错误的列表操作 3. 解决方案3.1 使用安全的访问方法3.2 循环时使用正确的范围 4. 预防措施4.1 编写单元测试4.2 动态检查列表长度 结语 引言 在Python中操作列表时,IndexError: list …

Web 版 | 开源数据库设计软件 | drawdb

文章目录 简介快速运行方式 1:本地运行方式 2:Docker 构建并运行方式 3:Docker 运行参考🚀 目标: 安装一个 Web 版本的 ER 图设计软件! 👉 GitHub: https://github.com/drawdb-io/drawdb 【11.7k ⭐】 简介 DrawDB:Free, simple, and intuitive database design …

算法学习笔记——二分搜索

二分搜索 在有序数组中确定num存在还是不存在&#xff1a; 当arr[m] num&#xff0c;则num存在当arr[m] > num&#xff0c;则 r m - 1&#xff0c;缩小r的范围&#xff0c;继续往左二分当arr[m] < num&#xff0c;则l m 1&#xff0c;缩小l的范围&#xff0c;继续往…

Android基础-进程间通信

在Android系统中&#xff0c;跨进程通信&#xff08;IPC&#xff0c;Inter-Process Communication&#xff09;是实现不同应用程序或同一应用程序中不同进程间数据共享和交互的关键技术。Android提供了多种IPC机制&#xff0c;每种机制都有其特定的使用场景和优缺点。下面将详细…

代码随想录算法训练营第36期DAY51

DAY51 121买卖股票的最佳时机 做过了。算是二刷&#xff1a;来自力扣优质题解 贪心&#xff1a; 每次记录更新最小点和最大出售值。 class Solution {public: int maxProfit(vector<int>& prices) { int cur,resINT_MIN,curminINT_MAX; for(int…

从军事角度理解“战略与战术”

战略与战术&#xff0c;均源于军事术语。 战略&#xff08;Strategy&#xff09;&#xff0c;源自希腊语词汇“strategos&#xff08;将军&#xff09;”和“strategia&#xff08;军事指挥部&#xff0c;即将军的办公室和技能&#xff09;”。指的是指挥全局性作战规划的谋略…

【位运算】【前缀和】个人练习-Leetcode-1177. Can Make Palindrome from Substring

题目链接&#xff1a;https://leetcode.cn/problems/can-make-palindrome-from-substring/description/ 题目大意&#xff1a;给出一个字符串s&#xff0c;每次query给出l, r, k&#xff0c;要求判断子串s[l:r1]在经过k次操作后是否能变为回文串。一次操作可以将子串内的一个字…