【C++进阶】深入STL之string:模拟实现走进C++字符串的世界
📝个人主页🌹:Eternity._
⏩收录专栏⏪:C++ “ 登神长阶 ”
🤡往期回顾🤡:C++模板入门
🌹🌹期待您的关注 🌹🌹
❀STL之string
- 📒1. string类的成员变量
- 📒2. string的构造函数
- 🎈无参的构造函数
- 🎩带参的构造函数
- 📒3. string的析构函数
- 📒4. string的拷贝构造函数
- 🔥 浅拷贝
- 💧 深拷贝
- 📒5. string类的运算符重载
- 📒6. string容量相关函数
- 📒7. string常用函数模拟
- ⭐查找
- ⭐ 添加
- 📒8. 总结
前言:在C++中,string是一个极其重要且常用的类,它为我们提供了丰富的字符串操作功能。然而,了解其背后的实现原理,不仅可以帮助我们更好地使用它,还能让我们对C++的内存管理、模板编程等有更深入的理解。本文将带你走进C++字符串的世界,通过模拟实现一个简单的string类,来探索其内部机制
模拟实现string类,最主要是实现string类的构造、拷贝构造、赋值运算符重载以及析构函数
📒1. string类的成员变量
首先我们要先搞清楚string的成员变量,我们清楚string类在底层实际上就是一个字符指针,在模拟实现string之前,我们创建一个属于自己的命名空间来与库里面的区分
namespace pxt
{class string{public:const char* c_str() const // 为了能更好的实现,我们提前实现以下c.str{return _str;}private:// 成员变量char* _str; // 指向一段空间的指针size_t _size; // 有效字符串长度size_t _capacity; // 空间总大小};
}
📒2. string的构造函数
🎈无参的构造函数
string():_str(new char[1]{ '\0' }),_size(0), _capacity(0)
{}
注意:在调用无参的构造函数时,库里面并不只是开了空间,它还干了其他事情,所以我们在自己模拟现实时,一定不能用nullptr
去初始化,否则就会出错,因此我们放一个'\0'
进去!
std::string无参构造:
🎩带参的构造函数
string(const char* str = ""):_size(strlen(str)), _capacity(_size)
{_str = new char[_capacity + 1];strcpy(_str, str);
}
在带参的构造函数因为常量字符串最后自带了一个'\0'
,因此我们什么都不用带
📒3. string的析构函数
~string()
{delete[] _str;_str = nullptr;_size = _capacity = 0;
}
string的析构函数非常简单,只需要将空间用delete
释放,并且将各个指针置为空,将空间大小变为0
📒4. string的拷贝构造函数
🔥 浅拷贝
首先我们来看一段拷贝构造的模拟实现:
// 拷贝构造
string(const char* str = "")
{if (nullptr == str){return;}_str = new char[strlen(str) + 1];strcpy(_str, str);
}// 测试
void test_string()
{string s1("hello world");string s2(s1);
}
为什么会引发异常呢?
我们发现s1和s2都指向都一块空间,在释放时同一块空间是不可以被释放多次的
,从而引起了崩溃,而这就是浅拷贝!
浅拷贝: 也称位拷贝,编译器只是将对象中的值拷贝过来。如果对象中管理资源,最后就会导致多个对象共享同一份资源,当一个对象销毁时就会将该资源释放掉,而此时另一些对象不知道该资源已经被释放,以为还有效,所以当继续对资源进项操作时,就会发生发生了访问违规,
可以采用深拷贝解决浅拷贝问题,即:每个对象都有一份独立的资源,不要和其他对象共享
💧 深拷贝
// 我们用s作为s1的别名
string(const string& s)
{_str = new char[s._capacity + 1];strcpy(_str, s._str);
}
深拷贝:每个对象都有一份独立的资源,不要和其他对象共享
注意: 关于浅拷贝一定要引起重视!
📒5. string类的运算符重载
operator=
在operator=
上,我们有两种写法
// 传统写法
string& operator=(const string& s)
{if (this != &s){char* tmp = new char[s._capacity + 1]; // 存放'\0'strcpy(tmp, s._str);delete[] _str;_str = tmp;_size = s.size();_capacity = s.capacity();}return *this;
}// 现代写法
string& operator=(string s)
{swap(_str, s._str); // swap库中存在,可以直接使用return *this;
}
传统写法
- 传统写法函数的运用引用传参,通过创建中间变量,并开辟空间然后将参数拷贝进中间变量,再把这个中间变量的地址传给this,从而实现了operator=的功能
现代写法
- 现代写法使用了库中的swap函数,从而让函数达到一个简洁的目的,该函数的参数是一个临时拷贝变量,深拷贝后,通过swap交换即可
operator<, operator==
bool operator<(const string& s) const
{return strcmp(_str, s._str) < 0; // 使用strcmp来比较字符串大小
}bool operator==(const string& s) const
{return strcmp(_str, s._str) == 0;
}
关于比较我们就讲这两个,对于其他的都可用operator<, operator==
去进行推导!
📒6. string容量相关函数
size,capacity,resize,reverse
size_t size() const
{return _size;
}size_t capacity() const
{return _capacity;
}
size,capacity这两个函数的模拟实现相对简单,我们简单实现一下就可以
void reserve(size_t n)
{if (n > _capacity) // n < _capacity时,reserve不会作出回应{char* tmp = new char[n + 1];strcpy(tmp, _str);delete[]_str;_str = tmp;_capacity = n;}
}
reverse只会改变capacity的大小,并不会改变size的大小
void resize(size_t n, char ch = '\0')
{if (n < _size) // 当 n < _size时会将size变小到n{_str[n] = '\0';_size = n;}else // 当 n > _size时,就和reserve类似{reserve(n);while (n < _size){_str[_size++] = ch;}_str[_size] = '\0';}
}
resize与reserve类似会改变size大小,但是也会改变capacity大小
📒7. string常用函数模拟
⭐查找
// 查找单个字符
size_t find(char ch, size_t pos = 0)
{for (size_t i = pos; i < _size; i++){if (_str[i] == ch){return i;}}return npos;
}
// 查找字符串
size_t find(const char* sub, size_t pos = 0)
{// strstr为字符串匹配函数const char* p = strstr(_str + pos, sub);if (p){return p - _str;}else{return npos;}
}
// 返回以pos开头,len位置结尾的字符串
string substr(size_t pos, size_t len = npos)
{string s;if (len == npos || len + pos > _size){len = _size - pos; }reserve(len);for (size_t i = pos; i < _size; i++){s += _str[i];}return s;
}
⭐ 添加
// 尾插单个字符
void push_back(char ch)
{if (_size == _capacity){reserve(_capacity == 0 ? 4 : _capacity * 2);}_str[_size] = ch;++_size;_str[_size] = '\0';
}
// 插入字符串
void append(const char* str)
{size_t len = strlen(str);if (_size + len > _capacity){reserve(_size + len);}strcpy(_str + _size, str);_size += len;
}string& operator+=(char ch)
{push_back(ch);return *this;
}string& operator+=(const char* str)
{append(str);return *this;
}
因为在添加中+=既可以添加字符也可以添加字符串,往往在日常中的使用频率是最高的,所以推荐大家使用+=来代替
push_back
和append
📒8. 总结
经过对STL中string的深入探索与模拟实现,我们仿佛揭开了一个隐藏在C++深处的奇妙世界。这个旅程不仅让我们对string这一基础数据类型有了更为深刻的理解,也让我们领略了STL背后的设计理念与精巧实现,让我们携手共进,共同走进C++字符串的奇妙世界!
谢谢大家支持本篇到这里就结束了,祝大家天天开心!
相关文章:

【C++进阶】深入STL之string:模拟实现走进C++字符串的世界
📝个人主页🌹:Eternity._ ⏩收录专栏⏪:C “ 登神长阶 ” 🤡往期回顾🤡:C模板入门 🌹🌹期待您的关注 🌹🌹 ❀STL之string 📒1. string…...

go语言linux安装
下载:https://go.dev/dl/ 命令行使用 wget https://dl.google.com/go/go1.19.3.linux-amd64.tar.gz解压下载的压缩包,linux建议放在/opt目录下 我放在/home/ihan/go_sdk下 sudo tar -C /home/ihan/go_sdk -xzf go1.19.3.linux-amd64.tar.gz 这里的参数…...

vi和vim有什么不同?
vi 和 vim 都是流行的文本编辑器,它们之间有以下主要区别: 历史: vi 是一个非常古老的文本编辑器,最初由 Bill Joy 在 1976 年为 Unix 系统编写。vim(Vi IMproved)是 vi 的一个增强版,由 Bram M…...

CSS动画效果(鼠标滑过按钮动画)
1.整体效果 https://mmbiz.qpic.cn/sz_mmbiz_gif/EGZdlrTDJa5SXiaicFfsrcric7TJmGO6YddqC4wFPdM7PGzPHuFgvtDS7MIvnLHB4WFaKia0Qh8VCyUaoyHMc2Zltg/640?wx_fmtgif&fromappmsg&tpwebp&wxfrom5&wx_lazy1&wx_co1 网页设计中的按钮不仅是用户交互的桥梁&#…...

数据结构(C):从初识堆到堆排序的实现
目录 🌞0.前言 🚈 1.堆的概念 🚈 2.堆的实现 🚝2.1堆向下调整算法 🚝2.2堆的创建(堆向下调整算法) ✈️2.2.1 向下调整建堆时间复杂度 🚝2.3堆向上调整算法 🚝2.…...

ChatGLM3-6B部署
ZhipuAI/chatglm3-6b 模型文件地址 chatglm3-6B-32k-int4 量化的模型地址 ChatGLM3 代码仓库 ChatGLM3 技术文档 cpolar http xxx 端口 /anaconda3/envs/chatglm2/lib/python3.8/site-packages/gradio$ networking.py 硬件环境 最低要求: 为…...

代码随想录35期Day54-JavaScript
Day54题目 ### LeetCode739每日温度 核心思想:今天主要是学会单调栈的使用.找到比元素更大的下一个元素,如果比栈顶元素小就入栈,否则就出栈顶元素,当前元素就是比栈顶元素大的"下一个更大的元素". /*** param {number[]} temperatures* return {number[]}*/ var …...

把自己的服务器添加到presearch节点
Presearch is a scam. Before, judging by the price of the token you should have been able to get between $150-$200 after 12-13 months of regular searches. "If you use this service for the next 11 years you will have earned $30!" Presearch大约需要…...

Open3D(C++) OTSU点云二值化
目录 一、算法原理二、代码实现三、结果展示1、原始点云2、二值化本文由CSDN点云侠原创,原文链接。如果你不是在点云侠的博客中看到该文章,那么此处便是不要脸的爬虫与GPT。 一、算法原理 最大类间方差法(Between-class scatter method)是一种用于分割的方法,它通过计算图…...

浔川python社获得全网博主原力月度排名泸州地区第二名!
今日,浔川python社在查看全网博主原力月度排名泸州地区时,一看就震惊啦! 全网博主原力月度排名泸州地区排名榜单 全网博主原力月度排名泸州地区第二名为:浔川python社。 感谢粉丝们的支持!浔川python社还会继续努力&a…...

第二站:Java——集合框架的深邃海洋(续)
### Java——集合框架的深邃海洋(续) 在我们的Java集合框架探索之旅中,我们已经涉足了基本操作、高级特性,现在让我们深入探讨一些特定场景下的应用和进阶技巧,比如集合的分区操作、分组、并行流的性能考量࿰…...

linux系统下,mysql增加用户
首先,在linux进入mysql mysql -u root -p 然后查看当前用户: select user,host from user; 增加用户语句: CREATE USER 用户名host范围 IDENTIFIED BY 密码;...

Java数据结构与算法(最长回文子串中心扩散法)
前言 回文子串是练习数据结构和算法比较好的使用场景,可以同时练习到双指针、动态规划等一些列算法。 实现原理 中心扩散算法实现。这里定义最长回文子串长度的大小为maxLen,起点位置为0. 奇数个数为中心点和偶数个数为中心点分别计算回文长度大小。…...

基于Python网络招聘数据可视化分析系统的设计与实现
基于Python网络招聘数据可视化分析系统的设计与实现 Design and Implementation of Python-based Network Recruitment Data Visualization Analysis System 完整下载链接:基于Python网络招聘数据可视化分析系统的设计与实现 文章目录 基于Python网络招聘数据可视化分析系统的…...

【Linux】Linux工具——gcc/g++
1.使用vim更改信用名单——sudo 我们这里来补充sudo的相关知识——添加信任白名单用户 使用sudo就必须将使用sudo的那个账号添加到信用名单里,而且啊,只有超级管理员才可以添加 信用名单在/etc/sudoers里 我们发现它的权限只是可读啊,所以…...

【惯性传感器imu】—— WHEELTEC的惯导模块的imu的驱动安装配置和运行
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、IMU驱动安装1. 安装依赖2. 源码的下载3. 编译源码(1) 配置固定串口设备(2) 修改luanch文件(3) 编译 二、启动IMU1. 运行imu2. 查看imu数据 总结 前言 WHEE…...

Linux提权一
#信息收集 当前主机的操作系统 hostnamectl cat /etc/*-release lsb_release -a cat /etc/lsb-release # Debain cat /etc/redhat-release # Redhat cat /etc/centos-release # Centos cat /etc/os-release # Ubuntu cat /etc/issue 当前主机的内核版本 hostnamectl uname -a …...

Vue.js中如何实现以列表首列为表头
前言 一般情况table列表的展示,列头都在第一横行,此方法用于列头在第一列的情况。 效果图 核心代码 <template><div><table class"data-table"><tr v-for"(column, columnIndex) in columns" :key"col…...

如果孙宇晨和贾跃亭能够握手,或许将会上演新的戏码
就在贾跃亭宣布将进行个人IP的商业化不久,便迎来了回应,并且这一次给予贾跃亭回应的,同样是一个颇具争议性的人物——孙宇晨。 根据孙宇晨最新发布的视频显示,他愿意投资贾跃亭「做一个新的个人IP化的公司」,并且将会…...

渲染100为什么是高性价比网渲平台?渲染100邀请码1a12
市面上主流的网渲平台有很多,如渲染100、瑞云、炫云、渲云等,这些平台各有特色和优势,也都声称自己性价比高,以渲染100为例,我们来介绍下它的优势有哪些。 1、渲染100对新用户很友好,注册填邀请码1a12有3…...

Jenkins流水线pipeline--基于上一章的工作流程
1流水线部署 1.流水线文本名Jenkinsfile,将流水线放入gitlab远程仓库代码里面 2pipeline脚本 Jenkinsfile文件内容 pipeline {agent anyenvironment {key"value"}stages {stage("拉取git仓库代码") {steps {deleteDir()checkout scmGit(branches: [[nam…...

比较Rust和Haskel
在比较Rust和Haskell时,我们可以从多个维度来分析它们各自的优势。以下是Rust相对于Haskell的优势,以及Haskell相对于Rust的优势: Rust比Haskell强的方面: 内存安全与并发性: Rust通过独特的所有权系统和借用检查器在…...

RedisTemplate的Long类型使用increment自增报错
问题描述 代码如下 Resourceprivate RedisTemplate<String,String > redisTemplate;redisTemplate.opsForValue().set("testKey", 0L); redisTemplate.opsForValue().increment("testKey");工作里用Long类型存储评论数,在使用increment自…...

【代码随想录训练营】【Day 36】【贪心-3】| Leetcode 1005, 134, 135
【代码随想录训练营】【Day 36】【贪心-3】| Leetcode 1005, 134, 135 需强化知识点 题目 1005. K 次取反后最大化的数组和 贪心:翻转绝对值最小的数思路:将数组按绝对值降序排序后,从左向右遍历数组,如果遇到小于0的数并且还…...

2.7HDR与LDR
一、基本概念 1.基本概念 动态范围(Dynamic Range) 最高亮度 / 最低亮度 HDR High Dynamic RangeLDR Low Dynamic Range HDR与LDR和Tonemapping的对应关系: 我们常用的各种显示器屏幕,由于不同的厂家不同的工艺导致它们的…...

YOLOv5改进(五)-- 轻量化模型MobileNetv3
文章目录 1、MobileNetV3论文2、代码实现2.1、MobileNetV3-small2.2、MobileNetV3-large 3、运行效果4、目标检测系列文章 1、MobileNetV3论文 Searching for MobileNetV3论文 MobileNetV3代码 MobileNetV3 是 Google 提出的一种轻量级神经网络结构,旨在在移动设备上…...

用户流失分析:如何使用Python训练一个用户流失预测模型?
引言 在当今商业环境中,客户流失分析是至关重要的一环。随着市场竞争的加剧,企业需要更加注重保持现有客户,并深入了解他们的离开原因。本文探讨了用户流失分析的核心概念以及如何构建客户流失预测模型的案例。通过分析用户行为数据和交易模式…...

【计算机毕设】基于SpringBoot的社区医院信息平台设计与实现 - 源码免费(私信领取)
免费领取源码 | 项目完整可运行 | v:chengn7890 诚招源码校园代理! 1. 引言 随着医疗信息化的不断推进,社区医院作为基层医疗机构,需要建立高效、便捷的信息管理平台以提高服务质量和工作效率。基于SpringB…...

LLM——深入探索 ChatGPT在代码解释方面的应用研究
1.概述 OpenAI在自然语言处理(NLP)的征途上取得了令人瞩目的进展,这一切得益于大型语言模型(LLM)的诞生与成长。这些先进的模型不仅是技术创新的典范,更是驱动着如GitHub Copilot编程助手和Bing搜索引擎等广…...

Android中ANR的分析和解决
一 ANR概述 2、ANR的类型 (1)KeyDispatchTimeout(常见) input事件在5S内没有处理完成发生了ANR。 logcat日志关键字:Input event dispatching timed out (2)BroadcastTimeout 前台Broadcast…...