(C++)string类的模拟实现

  愿所有美好如期而遇


前言

我们模拟实现string类不是为了去实现他,而是为了了解他内部成员函数的一些运行原理和时间复杂度,在将来我们使用时能够合理地去使用他们。

为了避免我们模拟实现的string类与全局上的string类冲突(string类也在std命名空间中),我们用自己的命名空间包起来。

namespace A
{class string{static void test(){}}    
}int main()
{A::string::test();
}

接下来我们开始模拟实现string类。

私有的成员变量,我们设计无符号整型计算有效字符数量的_size,以及记录空间大小的_capacity,最后就是字符指针,我们将来开辟好一块空间后存放字符串,将由他来指向。

namespace A
{class string{private:size_t _size;size_t _capacity;char* _str;}    
}

构造函数:

默认是空串,并且我们默认比有效字符多开一个字节的空间,之后进行拷贝。

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

 拷贝构造函数:

我们模拟实现string类,一定会有空间的开辟,一但对象涉及到拷贝,就不能是浅拷贝,否则会出现一块空间两次释放,直接崩掉。

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

 赋值运算符重载:

同拷贝构造,对象也是不能值拷贝,否则会出现一块空间释放两次。
 

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

析构函数:

~string()
{delete[] _str;_str = nullptr;_capacity = _size = 0;
}

 将string转换为const char*,我们会在strlen等C的接口处使用,比如strlen(s.c_str()),因为strlen他的参数是const char*类型的。
 

const char* c_str() const
{return _str;
}

 四个迭代器

只有物理地址空间连续才可以像这样,如果是链表,我们不能这样做。

typedef char* iterator;
typedef const char* const_iterator;iterator begin()
{return _str;
}iterator end()
{return _str + _size;
}const_iterator begin()const
{return _str;
}const_iterator end()const
{return _str + _size;
}

 尾插单个字符,_capacity和_size都是只考虑有效字符,我们在创建空间时默认开空间比_capacity大一。

void push_back(char ch)
{if (_size == _capacity){_capacity = 0 ? 4 : _capacity * 2;char* tmp = new char[_capacity + 1];strcpy(tmp, _str);delete[] _str;_str = tmp;}_str[_size++] = ch;_str[_size] = '\0';
}

 reserve函数,我们使用reserve重新开空间,也是只考虑有效字符。

我们实现的reserve不可以缩容。

void reserve(size_t n)
{if (n > _capacity){char* tmp = _str;//比需求多开一个字节的空间_str = new char[n + 1];strcpy(_str, tmp);//别忘记_capacity_capacity = n;delete[] tmp;}
}

 尾插字符串

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+=(const string& str)
{append(str.c_str());return *this;
}string& operator+=(const char* str)
{append(str);return *this;
}string& operator+=(char ch)
{push_back(ch);return *this;
}

 成员函数swap

//不用进行深拷贝,直接交换地址和大小
void swap(string& s)
{std::swap(_size, s._size);std::swap(_capacity, s._capacity);std::swap(_str, s._str);
}

清空字符串函数

void clear()
{memset(_str, 0, _size);
}

返回有效字符数量 ,判断是否为空

size_t size()const
{return _size;
}bool empty()const
{return _size == 0;
}

重载[]运算符,我们重载两个版本的,重载const版本是因为我们有时候只读,不写,所以需要这样的重载。

char& operator[](size_t index)
{return _str[index];
}const char& operator[](size_t index)const
{return _str[index];
}

 find函数,找到后返回下标。strstr找到后返回的是找到的字符串的首地址,否则返回空。

size_t find(char c, size_t pos) const
{for (size_t i = pos; i < _size; i++){if (_str[i] == c){return i;}}return npos;
}//hello world
size_t find(const char* s, size_t pos = 0) const
{char* tmp = strstr(_str, s);if (tmp == nullptr){return npos;}return tmp - _str;
}

insert函数,从pos位置插入单个字符,以及字符串

string& insert(size_t pos, char c)
{assert(pos <= _size);if (_size == _capacity){_capacity = 0 ? 4 : _capacity * 2;char* tmp = new char[_capacity + 1];strcpy(tmp, _str);delete[] _str;_str = tmp;}int end = _size;while (end >= (int)pos){_str[end + 1] = _str[end];end--;}_str[pos] = c;_size++;return *this;
}//pos是下标
string& insert(size_t pos, const char* str)
{assert(pos <= _size);int len = strlen(str);if (len + pos > _capacity){reserve(len + pos);}int end = _size;while (end >= (int)pos){_str[end + len] = _str[end];end--;}strncpy(_str + pos, str, len);_size += len;return *this;
}

erase函数,删除从pos节点开始的len个字符

string& erase(size_t pos, size_t len)
{//如果pos == size就和没删除一样,相当于删\0assert(pos < _size);//从pos位置删除len个字符,也就是pos后的字符全部删掉//传的len值接近npos,pos+len可能溢出,也会有未知错误if (len == npos || pos + len >= _size){_str[pos] = '\0';_size = pos;}else{strcpy(_str + pos, _str + pos + len);_size -= len;}return *this;
}

substr,截取从pos位置开始长度为len的字符串 ,在他返回时,就是对象的值拷贝,会有临时对象产生,临时对象就需要我们自己写的拷贝构造函数了。

string substr(size_t pos = 0, size_t len = npos)
{assert(pos < _size);int end;string str;//hello world 2 3if (len == npos || pos + len > _size){end = _size;}else{end = pos + len;}//记得给str扩容str.reserve(end - pos);while (end > pos){str += _str[pos++];}return str;
}

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

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

相关文章

羊大师介绍,备孕阶段饮食规划及对羊奶的影响

备孕期是夫妻俩为了生育健康宝宝所准备的重要阶段&#xff0c;在这个阶段&#xff0c;营养的摄入对于双方的身体健康和胚胎的发育至关重要。而羊奶作为一种营养丰富的饮品&#xff0c;备孕期间是否能喝羊奶一直是备孕夫妇们关注的话题。本文小编羊大师将会详细解答这一问题&…

AIGC系列之:升级版的Stable Diffusion之SDXL介绍

目录 AIGC工具对比 DALL-E MidJourney Stable Diffusion 相关资料 SDXL介绍 SDXL生图效果 SDXL训练LoRA流程 AIGC工具对比 在目前的三大新兴文本转图像模型中&#xff0c;Stable Diffusion诞生得最晚&#xff0c;但由于拥有发展良好的开源社区&#xff0c;它的用户关注…

7 最大的以1为边界的正方形

来源&#xff1a;LeetCode第1139题 难度:中等 描述&#xff1a;给你一个由若干0和1组成的二维网格grid&#xff0c;请你找出边界全部由1组成的最大正方形子网格&#xff0c;并返回该子网格中的元素个数&#xff0c;若不存在&#xff0c;则返回0&#xff1b; 思路&#xff1a…

EasyExcel实现Excel百万级数据导入导出

1.1 模拟500w数据导出 需求&#xff1a;使用EasyExcel完成500w数据的导出。 500w数据的导出解决思路&#xff1a; 首先在查询数据库层面&#xff0c;需要分批进行查询&#xff08;比如每次查询20w&#xff09; 每查询一次结束&#xff0c;就使用EasyExcel工具将这些数据写入一…

【SpringBoot篇】使用Spring Cache高效处理缓存数据

文章目录 &#x1f339;简述Spring Cache&#x1f3f3;️‍&#x1f308;常用注解&#x1f33a;使用SpringCache&#x1f6f8;Cacheable注解⭐测试 &#x1f6f8;CacheEvict&#x1f38d;一次清理一条数据&#x1f38d;一次删除多条数据 Spring Cache是一个框架,只要简单加一个…

宠物网站的技术 SEO:完整指南

您是宠物行业网站的从业者吗&#xff1f;那么您一定知道&#xff0c;当人们寻找与宠物相关的资源时&#xff0c;在搜索引擎结果中排名靠前有多么重要。 这就是技术SEO的用武之地&#xff01;它正在调整您网站的后端代码和服务器配置&#xff0c;以在 SERP 中排名更高。 在此&…

redis的集群,主从复制,哨兵

redis的高可用 在Redis中&#xff0c;实现高可用的技术主要包括持久化、主从复制、哨兵和集群&#xff0c;下面分别说明它们的作用&#xff0c;以及解决了什么样的问题。 持久化&#xff1a; 持久化是最简单的高可用方法&#xff08;有时甚至不被归为高可用的手段&#xff09;…

splice()方法

splice(index,len,item)是vue中数组变异的方法之一&#xff0c;可以用来删除&#xff0c;更新&#xff0c;和增加数组内容参数: index&#xff1a;数组下标 len&#xff1a;替换/删除的长度 item&#xff1a;更新或增加的内容使用方法&#xff1a; 1、删除&#xff0c;当参数形…

SQL优化的总结

1. 编写高效的 SQL 语句 1.1 合理使用索引 - **索引类型&#xff1a;** 解释不同类型的索引&#xff08;B-Tree、哈希索引等&#xff09;的作用和适用场景。 - **选择和创建索引&#xff1a;** 根据查询需求和数据分布选择合适的列创建索引&#xff0c;避免过多或不必要的索…

2019年9月26日: Go生态洞察:发布Go模块

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…

如何保护 API 安全

为了收集有关 API 管理当前和未来状态的见解&#xff0c;我们邀请来自 18 家公司的 IT 专业人士分享他们的想法。我们问他们&#xff1a;“哪些技术和工具对于保护 API 最有效&#xff1f;” 他们告诉我们的是&#xff1a; 验证 我们经常向已知的 B2B 合作伙伴提供 API 访问权…

JavaScript创建枚举

相比直接写数字与字符串值&#xff0c;用枚举表示预定义范围的常量值有很多优点&#xff0c;这里就不做赘述了&#xff0c;但目前为止javascript并没有提供原生的enum类型&#xff08;typescript当然就支持&#xff09;&#xff0c;通常javascript会借助对象类型来等效实现enum…

lightdb substr函数支持浮点类型

背景 在信创适配中&#xff0c;从ORACLE迁移过来的程序使用了substr函数。 LightDB 23.4版本对该函数进行了增强。支持位置参数和长度参数使用number类型。 示例 使用substr(text, numeric, numeric)函数 declareline varchar(300) : 312456789009876543001000.00;acct va…

mac解压gz文件

我发现一个问题&#xff0c;比如我从GSE144136里下载的文件 这个结果是这样的&#xff0c;直接双击是没有用的 因此需要使用命令行 gzip -d GSE144136_GeneNames.csv.gz

猜数字游戏

需求目标 这个游戏窗口要求玩家猜一个1到100之间的数字。玩家可以在文本框中输入自己的猜测&#xff0c;并点击提交按钮进行验证。游戏会给出相应的提示&#xff0c;直到玩家猜中正确的数字为止。 效果 源码 /*** author lwh* date 2023/11/28* description 猜数字游戏**/ i…

基于springboot房地产项目设计流程管理系统

一、需求描述 该项目针对某房地产效果图公司的项目流程进行信息化管理。其目标是使得该公司的管理人员、普通员工、前台、能够对项目、员工&#xff08;包括主管&#xff09;、财务、工作业绩以及客户进行全方位的管理&#xff0c;并在此基础上能够挖掘员工潜力&#xff0c;能够…

C语言——输入 10 个数,分别统计其中正数、负数、零的个数

#include <stdio.h> int main() {int numbers[10]; // 存储输入的10个数int positive_count 0; // 正数计数器int negative_count 0; // 负数计数器int zero_count 0; // 零计数器// 输入10个数printf("请输入10个数&#xff1a;\n");for (int i 0; i …

AMP State Evolution的计算:以伯努利-高斯先验为例

AMP State Evolution (SE)的计算 t 1 t1 t1时&#xff0c; E ( t ) E [ X 2 ] \mathcal E^{(t)} \mathbb E [X^2] E(t)E[X2]&#xff0c;SE的迭代式为 τ r ( t ) σ 2 1 δ E ( t ) E ( t 1 ) E ∣ η ( t ) ( X Z ) − X ∣ 2 , Z ∼ N ( 0 , τ r ( t ) ) \begin{a…

HarmonyOS应用开发者基础认证考试(90分过)

此博文为HarmonyOS应用开发者基础认证考试的最后的大考&#xff0c;要求100分取得90分方可获取证书、现将考试的题库进行分享&#xff0c;希望能帮到大家。但是需要注意的是&#xff0c;题库会不定时的进行题目删减&#xff0c;但是大概的内容是不会进行改变的。真心希望这篇博…

历时三个月,我发布了一款领取外卖红包小程序

近几年&#xff0c;推广外卖红包爆火&#xff0c;各种推广外卖红包的公众号层出不穷。于是&#xff0c;我就在想外卖红包究竟是怎么一回事。就这样&#xff0c;我带着问题开始了关于外卖红包的研究。 在研究的过程中&#xff0c;我开始了解隐藏优惠券、cps等一系列相关的术语。…