目录
string出现背景
当我们编写 C++ 程序时,经常需要处理字符串。在早期的 C++ 中,通常使用字符数组来表示字符串,但是这种方式存在一些问题,比如需要手动管理内存、容易出错等等。为了解决这些问题,C++ 标准库引入了 string 类型。
string 类型是一个标准库容器,它提供了一组方便的操作接口,可以像普通变量一样使用,并且不需要手动管理内存。string 类型可以自动调整大小,并且支持多种字符串操作,比如拼接、查找、替换、插入等等。
除此之外,string 类型还具有良好的可移植性和高效性。它使用了许多优化技术来提高性能,并且在不同平台上都有相同的实现方式和行为。
编码标准
在使用 string 前,我们先来简单了解一下编码标准。最开始的编码标准是美国的 ASCII 码,它只包含了 128 个字符,包括英文字母、数字、标点符号和一些控制字符。由于 ASCII 码不能表示其他语言的字符,因此出现了万国码(Unicode),它支持世界上所有语言的字符,并且每个字符都有一个唯一的编号。
然而,Unicode 的缺点是占用空间太大,因此出现了一种压缩存储方式——UTF-8,它可以将 Unicode 编码压缩成可变长度的字节序列,并且向后兼容 ASCII 码。UTF-8 成为了互联网上最常用的编码方式之一。
在 C++ 中,string 类型默认使用 UTF-8 编码。除此之外,还有u16string,u32string和wstring,感兴趣的可以自己去看看。
大家知道中国的汉字用的是什么编码吗?
答案是:GDK编码
接下来我将用string来观察编译器底层通过调用编码表与文字的映射关系来进入我们今天的主题。
我们看到汉字的编码是一个负值,这说明了它采用的GDK编码,一般一个汉字占两个字节。
这个例子也很好的说明了这一点。
string成员函数
构造函数+拷贝构造
这里有一张c++98的string类的构造函数表,对于string和后续STL的学习,我的讲解方式是抓主要矛盾,并兼顾次要矛盾。
我们先来看1,2,4:
注意类初始化后跟=不一定是赋值重载,得根据两边是否为同一类型作为判断标准。这里的size()成员函数可以得到string的长度使其便利string并修改每个字符。
重载了cout和cin,我们可以用它直接输出整个string类。
(3)
第3个不太常用,第一个参数如果传常量字符串同样会有转换过程,从目标string的第n1个位置后开始拷贝n2个字符串,第三个参数是拷贝我故意取了个10,如果超出范围,默认结束。当然你也可以不给第三个位置参数,这里系统会传递一个缺省。
这里-1被size_t接收,意为整形的最大值,当然实际不可能有这么大的字符串~。
(5)
取前n个字符串进行构造(不常用)
注意s5和s6调用的是不同构造函数,s5是我们刚才介绍的第3个构造函数,不推荐像这样写,最好按照标准来写,以免发生混淆。
(6)
fill(填充)不常用
单个字符的填充 可以使用。
赋值重载
结合前面的知识不多赘述。
析构
没什么好讲的。
Capacity
先来看前两个,咦,怎么一样呢?
没错,它们就是一样的,感兴趣的可以了解一下这方面的演变过程,日常用size即可。
max_size
返回string的最大值(了解)
capacity
string的容量
在终端显示的容量为15,实际上有16个字节空间。(string没有计算\0)
empty为string判空,clear意为清除string的内容使之变空,从字面意义上很好理解。我们把resize放到下面来讲更好理解。
至于缩容shrink_to_fit,它会重新分配一块更小的内存,再将内容复制到新的空间,并释放原来的空间。对程序性能和效率有极大的影响 ,一般情况不推荐使用。
Modifiers
尾部插入
push_back意为在后面插入单个字符,append意为附加,不同于push_back可以插入一个字符串。string对append和push_back进行了一个封装,我们可以直接用+=来代替。
扩容
我们来看一下vs上string的扩容机制:
原理:string内的数据默认存到buf中,如果不够则进行扩容,堆上申请空间并清除buf上的内容。
class string//vs
{
private:
char* _ptr;
char _buf[16];
size_t _size;
size_t _capacity;
};
也就是说,当数据大小超出16时,就一次性在堆上申请32字节的空间给ptr,之后每次进行1.5倍的扩容。但这个机制在其他一些平台可能会有所不同,比如linux,大家可以自行尝试。
reserve
那有没有什么办法可以提前开好空间,节约时间提高效率呢?我们可以使用这个reserve函数,使用方法十分简单。
可以看到成功开辟了空间,由于编译的不同机制,开出的空间只可能比你给的要大,而不会小,实际没什么影响。
resize
与reserve相比,有什么不同呢?
是的,reside不仅改变了capacity,还改变了size,需要注意的是,如果resize的大小n小于原来的大小,将会只保留前n位,所以我们看到就算给st1传递了字符a但却没有任何意义。注意这里的缩减并不是指容量的缩减,而是size。 如果不传第二个参数,将会使用缺省 '\0'代替。