C++STL-string类的实现(上)

在上一篇中,我们知道了string类的一些基本使用,这一篇我们就说一下string类的具体的底层实现。
在这里插入图片描述

1.预前准备

首先,我们在string.h文件里面定义一个my_string命名空间域。
在这里插入图片描述
在里面实现一些最简单,最基本的内容。

1.1 初步的构造和析构

在这里插入图片描述

1.2 下标的运算符重载

这个函数比较简单,我们来看代码:
在这里插入图片描述
这里的返回值是引用,那么主要的作用就是为了可以达到修改的效果。
为了方便验证,我们再写两个函数:
在这里插入图片描述
因为我们没有写流插入和流提取的重载,但我们可以用这个获取等效的 C 字符串来打印。
在这里插入图片描述
从这里,我们可以看到进行修改了。准备工作做好了,就开始新的内容。

2. 深浅拷贝

2.1 拷贝构造函数

在编译器中,如果我们没有自己写拷贝构造那么编译器自己会默认生成一个拷贝构造函数。而默认生成的拷贝构造是浅拷贝也就是值拷贝
我们来看下面的代码:
在这里插入图片描述
从这里,我们可以看到程序崩溃了。为什么呢?
首先,这个程序的内存图是这样的:
在这里插入图片描述
在这里插入图片描述
从这里我们也可以清楚看见确实是值拷贝。为什么会程序崩溃有两点。
1.首先析构会析构两次。2.如果修改某一个另外一个也会被修改。

那么对这个问题,我们只能去写深拷贝:
在这里插入图片描述
在这里插入图片描述
从检验中,我们也可以看出程序没有崩溃,也没有一起被改变。

2.2 =运算符重载

赋值运算符重载和拷贝构造是一样的问题。
在这里插入图片描述
如果直接赋值就是把值复制过去,那么也会出现上面发生的问题。
我们也需要自己去写深拷贝:
在这里插入图片描述
在这里插入图片描述
从这里,我们可以看到并没有什么错误了。
但是这个代码还有一点问题:如果我们自己给自己赋值。
在这里插入图片描述
你会发现它出现乱码了。原因是这样的:
在这里插入图片描述
因为在这里,我们把s1的空间给先直接释放掉了,然后我们又给它开辟了s1相同大的空间,但前面我们给释放掉了,里面就是随机值,随机值会找到’\0’才结束,所以里面是乱码。
如果自己给自己赋值,我们需要判断一下:
在这里插入图片描述
但这样写,还有点瑕疵。就是如果new开辟失败了,那么s1自己也被销毁了。这样是不好的,如果开辟失败,s1也不会销毁才是好的。
在这里插入图片描述

3. 完善前面写的函数

3.1 完善构造函数和析构函数

在这里插入图片描述
在这里插入图片描述
增加这两个的目的就是为了可以增删查改。我们这里并没有算’\0’,计算的是有效的字符个数。
但我们还没有写这样的一个创建方式:
在这里插入图片描述
这样写我们没有给参数,默认的是一个空字符串,我们需要写一个全缺省的默认构造函数。
在这里插入图片描述
但我们可以把这两个放在一起写,成为一个全缺省的默认构造函数:
在这里插入图片描述

3.2 完善拷贝构造函数

在这里插入图片描述

3.3 完善下标运算符和赋值运算符重载

下标运算符:
在这里插入图片描述
赋值运算符:
在这里插入图片描述
但此时,下标运算符还差一个:
在这里插入图片描述
从这里,我们可以看出没有合适的下标运算符匹配。原因是:我们这里的对象s是被const修饰的,它是只能读,不能写的。而我们现在的[]运算符函数的对象是一个可读可写的。权限放大了,所以不行。我们还要再写一个:
在这里插入图片描述

3.4 返回有效字符大小和空间的函数

在这里插入图片描述

4. 增加的函数

4.1 reserve函数

在string类里面,reserve函数的意思是指定n的大小来扩容。
在这里插入图片描述
我们先开辟新的空间,然后将内容拷贝到新空间里,在销毁原来的空间,在把新空间赋给_str。

4.2 push_back函数

在string类里面,push_back函数就是插入一个字符。
在这里插入图片描述
在这里插入图片描述
从这里,我们可以看到是可以添加的,但是这里有一个bug。
在这里插入图片描述
如果,我们一开始没有开空间,那么这里就会出现崩溃,原因就是在上面的函数里,_capacity*2如果_capacity是0那么它永远都是0,所以会出现越界访问。

正确写法如下:
在这里插入图片描述

4.3 append函数

append函数在string类里面的作用是添加一个字符串或添加一个字符串对象。
在这里插入图片描述
因为在C++里面没有扩容函数,那么我们只能先算出它要添加的长度和现在长度的和,然后指定扩容到这里,然后再拷贝过来。
在这里插入图片描述
这个是追加一个对象的。

4.4 operator+=函数

这个函数就是复用push_back和append函数的。
在这里插入图片描述

4.5 resize函数

resize函数在string类里面有两部分作用:
1.扩空间+初始化。2.删除部分数据,保留前n个。
这个函数其实具有三种情况:
第一种情况:要开辟的空间n大于_capacity
在这里插入图片描述
假如,有一份空间的_capacity为15,里面已经有了hello world这11个字符。
如果我们要resize(20,‘x’),这个意思就是说要存20个有效数据。因为前面已经有了11个,我们扩容后,后面加9个x就行。
在这里插入图片描述
第二种情况:n小于_capacity,大于_size
在这里插入图片描述
如果我们要resize(14,‘x’),这里hello world已经有了11个字符,容量为15也够。所以只需要在后面添加3个x就行了。
在这里插入图片描述
第三种情况:n小于_size
在这里插入图片描述
如果我们要resize(5,‘x’),只保留有效字符前5个就行了。
在这里插入图片描述
实现的代码如下:
在这里插入图片描述

4.6 insert函数

insert函数在string类里面的意思是:在pos位置上插入。

4.6.1 插入一个字符

这个和我们在顺序表哪里是非常相似的。就是把pos位置往后的都向后移一位,然后在pos位置上插入就行了。
在这里插入图片描述
但是,这行代码还存在一些问题:
在这里插入图片描述
从这里,我们可以看出当头插时,程序崩溃。原因就是:当end为-1时,由于它是无符号类型,所以end就会成为最大整数,出现越界。
解决办法一:把end的类型和pos的size_t类型都改成int类型
在这里插入图片描述
解决办法二:将pos和end比较时,强制类型转换成int类型
在这里插入图片描述
解决办法三:将end指向’\0’后一个位置,每次是把前一个位置往后移,当end==pos结束
在这里插入图片描述

4.6.2 插入一个字符串

我们插入一个字符串,首先要扩容。然后将end指向最后一个位置,把end-len位置的数据往end位置上移。当end=pos+len-1时结束循环。
在这里插入图片描述

4.6.3 插入一个string类对象

插入一个string类对象和插入一个字符串是一样的道理。
在这里插入图片描述

4.7 earse函数

我们先来看一下标准库里面的函数:
在这里插入图片描述
这里有一个npod,它在string类里面是一个静态的成员变量。意思是:如果我们没有自己输入len就会默认len为npos,则把pos位置以后的数据全删了。现在,我们把这个静态成员变量给写上。
在这里插入图片描述
这个该怎么删除呢?有两种情况,我们来分析一下:
第一种情况:len+pos>=_size

在这里插入图片描述
像这种情况,是比较简单的,我们只需要将pos位置的值直接为’\0’就行了。
在这里插入图片描述
第二种情况:len+pos<_size
在这里插入图片描述
此时,我们需要将begin开始往后的数据,一个一个的往pos位置往后移。
在这里插入图片描述

5. 一些比较函数

在这里插入图片描述
这些函数都比较简单,但是这些函数不是写在类里面的,而是写在类外的。因为,我们这些函数不用访问类里面的私有变量,而是通过c_str函数来访问的。

6. find函数

6.1 查找一个字符

在这里插入图片描述

6.2 查找一个字符串

在这里插入图片描述
最后是p-_str,感谢读者的指出错误

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

学代码的咸鱼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值