string模拟实现

整体逻辑:

1、构造函数,析构函数

2、遍历,size(),operator[],迭代器iterator

3、增删查改

push_back   append(串)   插入前需要检查容量,reserve()   再重载+=

insert(挪动时,size_t pos小心死循环下标为0,可以引入npos多一步判断)   

erase  find  substr     关系运算符重载

4、流插入、流提取 利用c_str打印

5、拷贝构造、赋值运算符重载

一、构造/析构

1、构造函数

string模拟实现_第1张图片

size_t len = strlen(str),避免多次strlen效率低。

构造空串时可以利用一个指向" "的指针,还可以写成全缺省。

string模拟实现_第2张图片

len为0,开1个空间,把\0拷贝过去。

2、析构函数 

string模拟实现_第3张图片

先释放_str指向的空间,然后系统自动回收内置类型。 

二、遍历相关

1、[],size()

string模拟实现_第4张图片

operator[]返回的是char&,const版本可以让const对象调用,只读。

string模拟实现_第5张图片 2、迭代器iterator

string模拟实现_第6张图片

在string中,iterator是原生指针char*。

分别定义char*为iterator,const char* 为 const_iterator,两种迭代器是两种不同的类型。

两个begin()函数,以const为区分。

注:这里的const修饰的是string对象,是string对象是否加const,对应其调用的begin()函数是否加const

string模拟实现_第7张图片

 如果是s1使用cit遍历,调用的是没有const修饰的begin函数,返回的是iterator,理论上是可以修改的,但是接收的是const_iterator权限缩小,最终的效果也是没有修改。

只有当const对象s2使用cit遍历时,const对象对应const修饰的begin函数,返回的也是const_iterator,达到只读效果。

 本质上,const修饰的是*this这个对象,也就是之前说过的const对象只能调用const修饰的成员函数。

三、插入系列

1、reserve

string模拟实现_第8张图片

只扩大容量,不缩容。

 strcpy只拷贝到第一个\0结束。

对于”hello\0world”需要用memcpy,_size+1是为了把最后的\0也拷贝过去

2、push_back

string模拟实现_第9张图片

先检查是否需要扩容,容量为0时给一个初始值为4

尾插后,将原来的\0覆盖了,不要忘记再补上。 

3、append

 string模拟实现_第10张图片

append是追加一个串,为了避免重复扩容,先算一下串的长度len(如果需要就增容)

然后将str拷贝到_str+_size后。

这里用的是char* str,所以strcpy和memcpy相同。

4、重载+= 

string模拟实现_第11张图片

+=一个字符,复用push_back

+=一个字符串,复用append

5、resize 

调整_size并初始化,必要时也会调整_capacity

string模拟实现_第12张图片

6、insert 

string模拟实现_第13张图片

插入一个字符c时,先检查容量。

然后从_size开始把[pos,_size]往后移一个,包括_size位置的\0

头插时,防止size_t的end越界,必须让end>pos才能进入循环 

string模拟实现_第14张图片

 insert一个字符串时,先得到len,然后检查是否需要扩容。

然后将[pos,_size]向后移动len个单位到[pos,+len,_size+len]

最后将str全部拷贝到[pos,pos+len-1],共len个,不包含\0

string模拟实现_第15张图片

也可以加上npos来判断

7、erase 

string模拟实现_第16张图片

第二种情况将[pos+len,_size]往前移动len个单位即可。 

8、find

string模拟实现_第17张图片

找某个字符c从某个位置pos出现的第一个位置

直接从pos开始遍历,找到后返回下标即可。

string模拟实现_第18张图片

 利用库里的strstr函数,从_str+pos的位置开始找子串s

找到返回找到的下标,没找到返回nullptr。

找到时,ptr-_str指针相减,得到之间相差的元素个数,即下标位置。

9、substr

string模拟实现_第19张图片

当截取长度过长时,调整realLen为_size-pos,即截取pos后所有(不包括\0)

然后从pos位置开始截取共reaLen个字符。

10、关系运算符重载 

string模拟实现_第20张图片

对于<操作符,保证都在范围内比较。

比较出来大于和等于都返回false。

一直相等到一个结束,此时size()短才小于。

string模拟实现_第21张图片

优化后,先利用memcmp比较size个字符得到结果

ret为0时扔比较两个的长度,不为0时看ret比较出来的结果,<0则为true

string模拟实现_第22张图片

strcmp只能比较C字符串,不能比较string所有情况。如hello\0world这样中间带\0的

四、输入输出 

1、c_str

string模拟实现_第23张图片

返回C形式的字符串,可以直接cout打印

2、cout

string模拟实现_第24张图片

[0,_size]都打印,包括其中的\0 

3、cin

string模拟实现_第25张图片

string模拟实现_第26张图片

string模拟实现_第27张图片

拿到空格和\n后才能结束循环。

string模拟实现_第28张图片 五、拷贝构造/运算符重载

1、传统写法

string模拟实现_第29张图片

string模拟实现_第30张图片

2、现代写法

string模拟实现_第31张图片 string模拟实现_第32张图片

先构造出一个局部的string tmp,然后通过string中的swap函数,交换tmp和*this的成员(浅拷贝)

销毁时,局部的tmp会自动调用析构函数(*this必须先初始化一下,不能把脏数据给tmp析构)

帮忙清理资源。而*this则是一个拷贝好的string。

注:这里用的是string中的swap,浅拷贝交换它们的成员。如果用算法库中的swap,会创建出一个中间对象string,完成深拷贝,效率低。

string模拟实现_第33张图片

直接拷贝构造出一个str,然后swap交换。

此时如果用算法库里的swap,会调用负值重载,导致栈溢出。

3、写时拷贝 

string模拟实现_第34张图片

 只读时,为浅拷贝,地址相同。

修改时,引用计数-1,重新开空间完成一次深拷贝

引用计数为1时才析构,平时计数-1.

目录

整体逻辑:

一、构造/析构

1、构造函数

2、析构函数 

二、遍历相关

1、[],size()

​编辑 2、迭代器iterator

三、插入系列

1、reserve

2、push_back

3、append

4、重载+= 

5、resize 

6、insert 

7、erase 

8、find

9、substr

10、关系运算符重载 

四、输入输出 

1、c_str

2、cout

3、cin

​编辑 五、拷贝构造/运算符重载

1、传统写法

2、现代写法

3、写时拷贝 


你可能感兴趣的:(C++人生,算法,c++)