C++ string类详细讲解:从原理讲解到实战应用

目录

一.string的使用

1.1string常见的成员函数

1.2string的遍历和修改

二.迭代器

三.auto和范围for

3.1auto关键字

3.2范围for


一.string的使用

string接口很多,现在大概有120个成员函数接口(公开提供使用的,内部肯定不止),我文章中只写最常用的20-30个,其余的在用的时候查文档就好了

string是用字符的顺序表实现,因为要兼容C语言,所以C++字符串的后面有'\0'

下面是string常见的几种构造函数:

1.1string常见的成员函数

这里的析构函数会自动调用,这里就不详细说明了

下面讲解赋值:

这里我们回顾之前所学的拷贝构造和赋值构造的区别:

1.2string的遍历和修改

得益于运算符重载operator ,有了它可以让对象可以像数组一样使用,像string的底层就是数组,就可以用下标来访问对应位置的那个值

重载两个版本(一个普通版本一个const版本)是因为string有普通对象有const对象,const对象只能调用const成员函数,const成员函数返回const引用,返回对应字符的别名,但是不能修改

下面大概看一下string::operator 内部逻辑的样子,虽然底层是个模板,但模板只是字符串的字符类型不同而已,下面这个是手搓的

之前的文章写引用做返回值,更多的作用是减少拷贝,因为传值返回是返回返回对象的一个拷贝,这里体现了引用返回的另外一个功能,可以修改返回对象,达到了可以像数组一样操作

C++这里这样的实现方式还有一个很好的效果,C语言普通数组的越界检查是一种抽查,比如说在下面红框数组的结束设置一些标记位,只要这些标记位没有被修改,就不会报错。如果往后越界的很远修改就检查不到,这个是C语言数组的一大缺陷

C++这里转换为函数调用就可以使用assert(pos<_size)做越界检查

下面是三种遍历字符串,第一种我们已经讲解过,后面两种下面有详细介绍:

二.迭代器

迭代器用起来是一个行为像指针的东西,要找开始位置的指针(指向第一个有效数据),该指针是由一个叫begin的函数提供的,begin是提供开始位置的迭代器

还有一个指针end,这是最后一个字符的下一个位置,就是指向'\0'位置的指针,指向有效位置的下一个位置,'\0'不算有效字符,而是一个标识字符(标识字符串的结束)

但是迭代器不能等价于指针,只是行为像指针,不同容器不同版本的的迭代器都不同,包括string的实现也一样

迭代器也有普通版本和const版本

前面如果一个函数不会修改成员变量就写为带const的,普通对象和const都可以调用。带const和不带const的二者都要实现进行重载的情况就是既要读又要写,读写要分离。const对象只能读,普通对象既可以读又可以写,前面的 就是这样

const迭代器不是在普通对象前面加const,const string::iterator it1 = s.begin(); const 对象不是使用const iterator去遍历,因为这里const修饰的是迭代器本身,就不能++了,也就不能遍历了

所以图中const_iterator是类比第二个指针,迭代器本身是可以修改的,本身不被const修饰,而指向的内容被const修饰,不能修改

正确的写法是

const迭代器的特点就是不能修改

除了begin两种迭代器,还有两种迭代器

iterator叫做正向迭代器,它的遍历是从前向后的,该迭代器叫反向迭代器,普通对象用反向迭代器,const对象用const反向迭代器,reverse是逆置,反向,反转的意思

rbegin,rend返回的就是反向迭代器,这里rbegin的++能倒着走是因为封装重载运算符了,从底层实现的角度,迭代器的实现一定是依赖于指针的实现

迭代器还有cbegin和cend的版本,这两个版本是C++11增加的版本,它和const版本的begin是一样的,cbegin是更规范一些,在C++11之后,期望调用const迭代器就调用cbegin,分工更加清晰

所以迭代器有两大优点:

  1. 提供统一的方式遍历修改容器
  2. 算法可以泛型化,算法借助迭代器处理容器的数据

三.auto和范围for

3.1auto关键字

在这里补充2个C++11的小语法,方便我们后面的学习。

  • 在早期C/C++中auto的含义是:使用auto修饰的变量,是具有自动存储器的局部变量,后来这个 不重要了。C++11中,标准委员会变废为宝赋予了auto全新的含义即:auto不再是一个存储类型 指示符,而是作为一个新的类型指示符来指示编译器,auto声明的变量必须由编译器在编译时期 推导而得。
  • 用auto声明指针类型时,用auto和auto*没有任何区别,但用auto声明引用类型时则必须加&
  • 当在同一行声明多个变量时,这些变量必须是相同的类型,否则编译器将会报错,因为编译器实际 只对第一个类型进行推导,然后用推导出来的类型定义其他变量。
  • auto不能作为函数的参数,可以做返回值,但是建议谨慎使用
  • auto不能直接用来声明数组

前面有时候迭代器遍历的时候,迭代器很长很难写,就可以使用auto

但是这样写auto也一定程度降低了程序的可读性,一眼看去可能看不出来是什么类型对象的迭代器,所以要适度使用

3.2范围for

  • 对于一个有范围的集合而言,由程序员来说明循环的范围是多余的,有时候还会容易犯错。因此C++11中银日了基于范围的for循环。for循环后的括号由冒号":"分为两部分,第一部分是范围内用于迭代的变量,第二部分则表示被迭代的范围,自动迭代,自动取数据,自动判断结束
  • 范围for可以作用到容器对象上进行遍历

这里无法修改容器里的值的原因是范围for的方法是自动取容器中的数据,赋值给冒号前面的对象,该对象就是自动取的这个数据的拷贝,对对象进行改变是不会影响容器里的数据的,除非在被赋值的对象前加一个引用