c++领域展开第十五幕——STL(String类的模拟实现)超详细!!!!

c++领域展开第十五幕——STL(String类的模拟实现)超详细!!!!
在这里插入图片描述

文章目录

前言

上篇博客已经简单的介绍了string类的一些接口,并且做了一些了解
同时也刷了一些oj题目,熟练使用一些string的函数
今天我们来模拟实现一下string类
fellow me

string类的模拟实现

首先,string类是在stl库实现之前出现的,后面的stl库的内容大部分都和string类的接口类似
string类比起以前的一些数据结构,多了很多东西
迭代器就是一方面,能够更好的耦合算法和类和对象

string类——迭代器的模拟

我们先来看迭代器以及,string类的成员变量

classstring{public:typedefchar* iterator;//迭代器 begin endtypedefconstchar* const_iterator;constchar*c_str()const// 返回字符常量 {return _str;} iterator begin(){return _str;} iterator end(){return _str + _size;} const_iterator begin()const// 这里是const修饰的迭代器函数{// 在处理一些const修饰的对象时,如果直接访问上面的普通begin return _str;// 会引发权限的 放大 导致程序不能执行 所以这里复写了const的版本} const_iterator end()const{return _str + _size;} size_t size()const// 返回大小 // 这里从const是修饰大小和容量不能被改变{// 权限能缩小 不会放大return _size;} size_t capacity()const// 返回容量{return _size;}private:// char* _str =nullptr;// 字符串 size_t _size =0;// 大小 size_t _capacity =0;// 容量conststatic size_t npos;// 模拟string类里面缺省参数的 npos参数};

string类——默认成员函数

构造函数、析构函数、拷贝构造、运算符重载

在string类标准库里面有好几个版本的构造函数
这里模拟实现了其中两个
析构函数还是比较简单的
主要是拷贝构造函数两个版本来实现

string::string(size_t n,char ch)// 初始化列表:_str(newchar[n +1]),_size(n),_capacity(n){for(size_t i =0; i < n; i++){ _str[i]= ch;} _str[_size]='\0';} string::string(constchar* str)// 构造函数 :_size(strlen(str)){ _capacity = _size; _str =newchar[_size +1];strcpy(_str, str);}string::~string()// 析构函数{delete[] _str; _str =nullptr; _size =0; _capacity =0;} string::string(const string& s)// 拷贝构造 正常我们就是这样实现拷贝构造{// 防止在一些占用空间的参数 比如字符串 _str =newchar[s._capacity +1];// 调用系统的拷贝构造,导致浅拷贝,多次析构同一位置strcpy(_str, s._str);// 引起程序崩溃 _size = s._size; _capacity = s._capacity;}// 这里提供一种新的实现方法 同时也更简单明了// 而且这里的swap函数还有其他的作用 能被复用void string::swap(string& s){ std::swap(_str, s._str); std::swap(_size, s._size); std::swap(_capacity, s._capacity);}// 现代写法 直接复用 string::string(const string& s)// 这里直接定义新的string 如果this和其交换{// 两种方法原理是一样的 string tmp(s._str);swap(tmp);}// 另外还有一个 销毁函数voidclear()// 销毁{ _str[0]='\0'; _size =0;}

下面就是运算符重载部分了

// s1 = s2// s1 = s1void string::swap(string& s){ std::swap(_str, s._str); std::swap(_size, s._size); std::swap(_capacity, s._capacity);} string& string::operator=(const string& s)// 赋值运算符重载{if(this!=&s){ string tmp(s._str);swap(tmp);// 现代写法就是直接复用swap//delete[] _str; // 传统的就是这样一步一步赋值给另外一个对象//_str = new char[s._capacity + 1];//strcpy(_str, s._str);//_size = s._size;//_capacity = s._capacity;}return*this;}// 处理string像访问数组一样 直接堆 [] 进行重载char&operator[](size_t pos)// []重载 {assert(pos < _size);return _str[pos];}constchar&operator[](size_t pos)const// const修饰 不能改变内容{assert(pos < _size);return _str[pos];}// 下面就是一些判断字符串大小的函数 比较大小的函数还是比较简单的bool string::operator==(const string& s)const{returnstrcmp(_str, s._str)==0;// 这里复用了c语言里面的 strcmp 比较函数}bool string::operator!=(const string& s)const{return!(*this== s);}bool string::operator<(const string& s)const{returnstrcmp(_str, s._str)<0;}bool string::operator<=(const string& s)const{return*this< s ||*this== s;}bool string::operator>(const string& s)const{return!(*this<= s);}bool string::operator>=(const string& s)const{return!(*this< s);}

string类——常用函数接口

这里模拟实现一些string类的常用接口函数
reserve、push_back、append、insert、erase、find、substr等接口
实现string的增删改查功能
话不多说,上代码

// reserve函数 预留空间 void string::reserve(size_t n){if(n > _capacity){//cout << "reserve:" << n << endl;char* tmp =newchar[n +1];// 如果原本的空间没有到达指定大小 strcpy(tmp, _str);// 扩容delete[] _str; _str = tmp; _capacity = n;}}// 尾插函数 可以做 +=单个字符的复用函数void string::push_back(char ch){if(_size +1> _capacity)// 如果空间不够 扩容{// 扩容reserve(_capacity ==0?4: _capacity *2);} _str[_size]= ch;// 正常尾插 ++_size; _str[_size]='\0';// 注意\0 结尾}// append函数 在字符串尾部接入字符串 可以做+=字符串函数的复用void string::append(constchar* str){ size_t len =strlen(str);if(_size + len > _capacity){// 扩容 size_t newCapacity =2* _capacity;if(_size + len >2* _capacity){ newCapacity = _size + len;}reserve(newCapacity);}strcpy(_str + _size, str); _size += len;}// +=字符串 和 += 字符 函数的重载 string& string::operator+=(char ch){push_back(ch);return*this;} string& string::operator+=(constchar* str){append(str);return*this;}// 插入函数 在pos 位置 插入 n 个 ch 字符void string::insert(size_t pos, size_t n,char ch){assert(pos <= _size);assert(n >0);if(_size + n > _capacity)// 判断扩容{// 扩容 size_t newCapacity =2* _capacity;if(_size + n >2* _capacity){ newCapacity = _size + n;}reserve(newCapacity);}// 挪动数据/* int end = _size; // pos为size_t 在和int比较时 int 会转为size_t 导致程序出错 while (end >= (int)pos) { _str[end + n] = _str[end]; --end; }*/ size_t end = _size + n;// 这样写代码更健壮 而且end不会到负数部分while(end > pos + n -1){ _str[end]= _str[end - n];--end;}for(size_t i =0; i < n; i++){ _str[pos + i]= ch;} _size += n;/*string tmp(n, ch); insert(pos, tmp.c_str());*/// 这里复用insert的 在pos位置插入字符串}// insert 在pos位置插入字符串void string::insert(size_t pos,constchar* str){//assert(pos <= _size);//size_t n = strlen(str);//if (_size + n > _capacity)//{// // 扩容// size_t newCapacity = 2 * _capacity;// if (_size + n > 2 * _capacity)// {// newCapacity = _size + n;// }// reserve(newCapacity);//}//size_t end = _size + n;//while (end > pos + n - 1)//{// _str[end] = _str[end - n];// --end;//} // 正常写法  size_t n =strlen(str);// 间接扩容insert(pos, n,'x');// 直接用前面的insert复用 先插入 n 个字符 然后再覆盖一下for(size_t i =0; i < n; i++){ _str[pos + i]= str[i];// 直接覆盖 // 这样的代码就简洁很多 复用性高 好溯源}}// 删除函数 erase 指定位置删除长度为 len 的字符串void string::erase(size_t pos, size_t len){if(len >= _size - pos){// 删完了 _str[pos]='\0'; _size = pos;}else{ size_t end = pos + len;// size_t防止int强转while(end <= _size){ _str[end - len]= _str[end];++end;} _size -= len;}}// find查找函数 查找一个字符 size_t string::find(char ch, size_t pos){for(size_t i = pos; i < _size; i++){if(_str[i]== ch){return i;}}return npos;}// 查找一个字符串 size_t string::find(constchar* str, size_t pos){constchar* p =strstr(_str + pos, str);// 这里复用c里面的strstr if(p ==nullptr){return npos;}else{return p - _str;}}//substr 截取字符串 string string::substr(size_t pos, size_t len){ size_t leftlen = _size - pos;if(len > leftlen) len = leftlen; string tmp;// 构造tmp tmp.reserve(len);for(size_t i =0; i < len; i++){ tmp += _str[pos + i];}return tmp;}

string类——输入输出重载

剩下最后一个有点麻烦但又还好的接口
重载输入流和输出流,另外还有getline这个函数

// 输出函数是比较简单的 ostream&operator<<(ostream& out,const string& s){for(auto ch : s){ out << ch;}return out;}// 输入函数就有很多地方需要处理了 istream&operator>>(istream& in, string& s){ s.clear();// 先清除s里面的内容 防止意外// 输入短串,不会浪费空间// 输入长串,避免不断扩容const size_t N =1024;// 如果输入很长的字符串 一步一步输入的话会不断扩容char buff[N];// 这里开一个字符数组存起来 后序直接 += 就行 大大减少了扩容一步到位int i =0;char ch = in.get();while(ch !=' '&& ch !='\n'){ buff[i++]= ch;if(i == N -1){ buff[i]='\0'; s += buff; i =0;} ch = in.get();}if(i >0){ buff[i]='\0'; s += buff;}return in;}// getline 输入字符串 直到指定字符截止 istream&getline(istream& in, string& s,char delim){ s.clear();const size_t N =1024;char buff[N];int i =0;char ch = in.get();while(ch != delim)// 如果字符不是指定截止字符 就一直输入{// 不管是空格还是\n buff[i++]= ch;if(i == N -1){ buff[i]='\0'; s += buff; i =0;} ch = in.get();}if(i >0){ buff[i]='\0'; s += buff;}return in;}

整个string类的模拟实现就差不多到这里啦

总结

今天把string类模拟实现了一遍
在模拟实现过程中,发现了很多的问题
比如哪些重复且作用相同的代码,复用问题
充分利用已有的一些东西,比如std::swap,这个在拷贝构造和赋值重载的时候用的很爽
还有就是一些优化,哪些地方一直构造会费时费力,哪些地方直接复用效果会更好而且效率高
还有就是一些简单的语法知识,比如不经意间的类型强转过程会有意想不到的误区
总之,在模仿中一步一步优化,一步一步学习
借前人之鉴,涨己人之学识,加油

种一棵树最好的时间是十年前,其次是现在
在这里插入图片描述

Read more

2026年RAG技术路线图:基于DeepSeek与Neo4j知识图谱构建企业智能体系

RAG的演进:为何图检索增强生成(GraphRAG)将主导2026年 检索增强生成(RAG)自问世以来经历了深刻变革,2026年标志着其向图检索增强生成(GraphRAG)范式的关键性转变。这一演进源于传统平面向量型RAG在满足企业级复杂推理和可靠决策支持需求方面日益凸显的局限性。 这一转型的核心驱动力是从平面向量相似性向复杂关系推理的跨越。传统RAG依赖向量嵌入来衡量查询与文档片段的语义相似性,但这种方法无法捕捉企业决策至关重要的实体、概念与事件间的复杂关联。相比之下,GraphRAG将信息构建为包含节点(实体)和边(关系)的知识图谱,使模型能够遍历并推理这些关联——解锁了平面向量RAG无法实现的多跳推理和上下文关系理解能力。 GraphRAG还解决了传统RAG的两大长期痛点:上下文窗口限制和“中间信息丢失”问题。随着企业查询日益复杂,需要更大的上下文窗口来整合相关信息,但即便是最先进的大语言模型(LLM)也存在有限的上下文容量。GraphRAG通过将结构化知识存储在外部图数据库中解决了这一问题,允许模型按需检索最相关的节点和关系,而非将大量文本塞入上下文窗口。此外,“中间信息

By Ne0inhk

一键部署Z-Image-Turbo:云端AI绘画不求人

一键部署Z-Image-Turbo:云端AI绘画不求人 你是不是也遇到过这样的场景:脑子里有个绝妙的画面,想把它画出来,但要么不会画画,要么打开专业绘图软件折腾半天,最后出来的效果还不如想象力的十分之一? 或者,作为内容创作者、电商运营,每天需要大量配图、海报,找图库要花钱,自己设计又太费时间,效率低得让人抓狂。 今天,我要给你介绍一个“神器”——Z-Image-Turbo 极速云端创作室。它不是一个复杂的软件,而是一个打包好的云端AI绘画应用。你不需要懂代码,不需要配置环境,甚至不需要高性能电脑,只需要点几下鼠标,就能拥有一个属于你自己的、能秒级生成高清大图的AI画室。 这听起来是不是有点不可思议?别急,跟着我,10分钟你就能亲手把它搭建起来,并画出第一张作品。 1. 为什么你需要这个“云端画室”? 在深入动手之前,我们先搞清楚,这个工具到底能帮你解决什么问题。 1.1 传统AI绘画的三大痛点 如果你之前尝试过一些AI绘画工具,可能会对这几个问题深有体会: 1. 部署复杂:想用开源的Stable Diffusion?光是安装Python、

By Ne0inhk
Flash Table实测:JAI赋能低代码开发,重塑企业级应用构建范式

Flash Table实测:JAI赋能低代码开发,重塑企业级应用构建范式

目录 * 🔍 引言 * 1.1 什么是Flash Table * 1.2 低代码平台的进化与FlashTable的革新 * ✨FlashTable背景:为什么需要新一代低代码平台? * 2.1 传统开发的痛点 * 2.2 低代码平台的局限 * 2.3 FlashTable的差异化定位 * 💻 FlashTable安装:Docker部署&Jar包部署 * 3.1 基础环境要求 * 3.2 Docker部署(推荐方案) * 3.3 Jar包部署(无Docker环境) * 3.4 常见问题 * 📚FlashTable功能深度评测:从案例看真实能力 * 4.1 数据孤岛?FlashTable 自动化匹配字段 * 4.2 FlashTable复杂表单的开发挑战 * 4.3

By Ne0inhk
【机器人】具身导航 VLN 最新论文汇总 | Vision-and-Language Navigation

【机器人】具身导航 VLN 最新论文汇总 | Vision-and-Language Navigation

本文汇总了具身导航的论文,供大家参考学习,涵盖2026、2025、2024、2023等 覆盖的会议和期刊:CVPR、IROS、ICRA、RSS、arXiv等等 论文和方法会持续更新的~ 一、🏠 中文标题版 2026 ✨ * [2026] SeqWalker:基于分层规划的时序视野视觉语言导航方法 [ 论文 ] [ GitHub ]   * [2026] UrbanNav:从网络规模人类轨迹中学习语言引导的城市导航方法 [ 论文 ] [ GitHub ]  * [2026] VLN-MME:面向语言引导视觉导航智能体的多模态大语言模型诊断基准 [ 论文 ] [ GitHub ]  * [2026] ASCENT: 实现楼层感知的零样本物体目标导航  [ 论文] [ GitHub ] 2025 😆 * [2025] ETP-R1:面向连续环境VLN的进化拓扑规划与强化微调方法 [ 论文 ] [ GitHub ] * [2025] NaviTrace:评估视觉语言模型在真实世界场景中的导航能力 [ 论文 ] [ GitHub ] * [2025]

By Ne0inhk