C++ string类的模拟实现

前言:

上一篇博客,介绍了string容器类的一些常用的接口函数,我们对string容器已经有了一部分的认识,接下我将介绍string类是如何模拟实现出来的,通过string类的模拟实现了解各个接口底层的实现,加强对string 容器的理解。

文章摘要

本文章从string空间结构、构造函数、赋值重载、析构函数、容量大小有关的函数接口、插入和删除有关的操作、下标遍历、迭代器、运算符重载、流插入流提取和一些常用的其他函数进行了实现和介绍。希望通过本片文章能够给大家带来收获,如发现问题欢迎评论区指正。感谢大家的阅读!

string的空间结构

先声明一个命名空间,防止与标准库中的string容器类冲突。

string类容器的本质就是一个字符数组,既然是一个字符数组那么就会涉及动态开辟空间以及一些扩容问题,我们通过定义一个字符指针 _str 方便进行动态空间的开辟,通过_size 记录数组中的元素个数,通过_capacity 记录数组的容量,有了_size 和 _capacity就是方便后续的扩容操作的判断。

string的构造函数

  • 默认构造函数

_size记录的是字符数组中元素的个数,字符串的存储的数据长度就是 '\0' 之前的元素,因此这里动态开辟的_capacity+1 这里的1就是为了存储'\0',这里解释一下为什么初始化列表中只将_size 进行初始化,不把  _capacity=_size  和_str 进行动态开辟空间的代码放到初始化列表进行,原因如下

假如某一天某一个糊涂蛋拿到我们的代码,将我们的成员变量 _size 和 _capacity 位置进行了互换,那么我们的构造函数就崩了,我们知道初始化列表是根据成员函数的声明顺序进的,_capacity 通过_size 进行赋值初始化,此时的 _size还是随机值,_capacity 也就是随机值,那么_str 进行动态开辟空间的就会崩掉。这里只将_size 进行初始化是为了增强代码的健壮性。

  • 通过c语言字符串进行拷贝构造

  • 拷贝构造函数

赋值重载

析构函数

容量和大小

  • 扩容(reserve)

如果所需要的空间n大于我们字符数组的容量时,我们进行扩容,代码的含义是,重新申请开辟一片空间,然后将原空间的数据进行拷贝到新空间,将原空间进行释放,_str指针指向新空间,原空间的数据个数是没有发生改变的,所以只更新一下_capacity即可。

  • 重新规划字符串的大小(resize)

识别字符串结束的条件就是遇到 '\0' ,当 n <字符串中的元素个数时需要进行缩容,缩绒的操作就是通过'\0' 将字符串进行中止。当n>字符串中的元素个数时,将字符 'c' 从原字符串末尾开始,一直到n前面的位置进行尾插,最后在n的位置补上 '\0' 作为结束标志。

  • 获取元素个数(size)

  • 获取数组容量(resize)

通过公有成员函数去使用私有成员变量,是这两个函数的意义。

插入和删除

  • 尾插(push_back)

插入元素首先应该考虑的就是扩容问题,通过附用reserve进行扩容。_size是数组中最后一个元素的下一个位置,也就是存放 '\0' 的位置,将元素进行插入这个位置,然后将'\0'放到下一个位置即可。

  • 尾插(append)

思路同上面的push_back,这里利用strcpy进行字符串拼接,注意strcpy进行字符串拼接时,并不hi将 '\0' 一同进行拷贝拼接,需要在最后进行补齐'\0'

  • 任意位置插入(insert)

数组任意位置进行插入操作步骤

①检查数组是否需要扩容

②进行挪动数据

③在指定位置进行插入元素

这里解释一下问题代码的问题,以及修正思路

问题:

注释掉的代码就是在挪动数据时出现了bug,我们进行挪动数据时从数组尾部元素一直到pos位置进行向后挪动,然后将新元素进行插入,这时候我们考虑当要在第零个位置进行插入时,将第零个位置元素进行挪动后 i--,i就变成了-1,但是i 的类型是无符号整形,无符号整形中 -1 代表整数中的最大值,循环因此就变成了一个死循环。

修正思路:

将挪动数据的起始位置向后进行挪动一个,判断条件就变成了 i>pos, 这时在位置为0的位置进行插入元素时,就可以完美避开死循环

  • 任意位置删除(erase)

分为两种情况,当没有进行给npos传参时,npos是给了缺省值的,在没有进行传参的时候就用缺省值进行pos位置及以后的删除;否则通过挪动数据删除pos位置的数据。

下标遍历

迭代器

迭代器分为普通迭代器和const迭代器,提供const迭代器防止string容器中的数据被改变。

运算符重载

一些其他函数

清空函数(clear)

查找函数(find)

交换函数(swap)

流插入和流提取

流插入(<<)

流提取(>>)

使用in.get()进行字符插入不适用cin>>的原因
流提取>>默认是跳过空格和换行的,所以>>永远无法读取空格和换行,程序会一直运行一直可以输入.如果字符串前面有空格或者换行,标准库的>>会默认清理空格和换行。所以要预先处理前面的空格和换行

刚开始调用clear 函数的原因
进行字符串资源的清理防止之前的数据影响我们手动进行插入时的数据

进行说明:
注释调的代码也是没有问题的,下面的代码主要是进行优化的作用,那么具体优化了哪些方面呢?通过一个buff字符数组,先将字符插入字符数组中,通过字符数组在进行插入,相当于插入字符串,可以减少扩容,提升性能。下面那个if语句是当最后一次数组没有充满,也要将数组中的数据进行插入。
 

整体代码

.h文件

.cpp文件


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值