string
1、auto
C++11规定了一个关键字:auto,auto通过初始化表达式的值类型,自动推导对象类型。
cpp
auto i = 10;//一般推导出int
auto j = 1.2;//一般推导出double
auto可以推导出指针类型。

上面的写法可以推导出int*类型,也可以推导出其它的类型。
然而,下面这样写,只能推导出int*类型:

auto也可以推导出引用类型,但是auto必须加上&,否则不能识别出引用类型:

可以看到,前三个地址相同,说明auto&推导出了引用类型;但是第四个地址不同,说明auto推导不出引用类型。
那么auto有什么用呢?
比如我们有一个string对象,然后又使用了迭代器:

我们写string迭代器类型,就需要写这么一个长长的东西。
这时我们用一个auto,去自动推导类型:

这就达到了简化代码的效果。
但是,频繁使用auto,会降低代码的可读性。我们要尽量避免通篇使用auto的情况发生。
2、范围for
C++11也规定了一个很新的语法,叫范围for。

范围for看上去自动实现了三步:
- 自动取容器数据赋值
- 自动迭代
- 自动判断是否结束
上面的代码只是打印了数据。如果我们要想改变数据,就需要使用引用:

上面的代码都是对stirng(和容器)操作。其实范围for也可以对数组操作:

范围for底层实现上,可能替换成了迭代器。
3、零碎接口(成员函数)
max_size()

max_size()返回的是对象可以达到的最大的存储元素的个数。
但是这个接口用得不多。
size()

size()返回的是对象实际存储有效元素的个数。

capacity()
capacity()返回的是对象当前最大空间(最多可以存多少个元素)。

clear()
顾名思义:清理内容(但不清理空间资源)。

void_pushback()
这是尾插接口。

4、string容量和实际大小的改变
我们创建一个s1,往里面放100个字符,然后观察一下s1容量的变化:


当前s1实际空间是16个字节,只不过最后一个字节存了一个\0,同时不显示出来,也不计入s1的实际内容。
我们可以看到,vs 2022的Debug版本下,s1扩容的规律是:
- 第一次扩容两倍
- 以后扩容1.5倍
STL的设计,其实是一种规范。STL规定的是要实现哪些容器、算法、接口...具体如何实现,取决于不同的平台。
Linux下,gcc的4.8.5版本,是二倍扩容:
C++提供了一个手动扩容的接口:reserve()
4.1、reserve()

划红线处,是两个细节:
- 如果输入的n大于原来的容量,那么reserve()可能会申请到相应的空间,甚至更大.
- 对于使用n缩小s1容量的请求是非绑定的,也就是不一定会缩小空间。
比如我们将原来的s1扩容到20个元素:

可以发现,扩的更多了。
我们又另外将s1缩容到五个元素:

可以发现,并没有缩容。这也与reserve()不会改变s1的内容相对应。
但是,我们还是建议,不要用reserve()缩容。(系统不会部分释放,必须异地缩容,造成性能浪费)
reserve()的核心作用,就是:假设有200个字符需要插入,那么就可以事先用reserve()开辟好空间,以减少自动扩容(多次异地扩容)带来的代价。
真要扩容,我们可以使用:shrink_to_fit()。
4.2、shrink_to_fit()

我们在vs2022和Linux(4.8.5)下看看shrink_to_fit()的作用:


我们可以看到,vs2022下没有缩容,Linux下进行了缩容。也就是说,缩容与否,取决于编译器。
一般情况下,我们还是不建议缩容,因为编译器不会释放部分空间,而是异地扩容,用时间换空间。
4.3、resize()
接口resize(),实现了对对象实际大小的改变。

我们前面的扩缩容,不会改变size()。但是resize()不一样。
如果输入参数n小于对象的size(),那么对象的前n个元素会被保留,其余的会被删除:

如果n大于,就会扩容;如果又指定字符,那么剩余空间就会用这个字符填充:

5、string的修改
5.1、append()
append()是一个追加内容的接口。

值得注意的是,如果追加的内容超过了当前对象的剩余容量,对象会扩容:



append()还可以使用迭代器传参,追加的内容是对应对象的迭代器区间的内容:

5.2、operator+=
operator+=也可以追加内容,并且它被重载成了成员函数:


operator+没有重载成成员函数。
原因是:operator+没有重载成成员函数,就可以实现以下操作。
要是operator+重载成了成员函数,那么第一个参数默认是对象(const指针),那么就不会有写法2,就不灵活了。
operator>等比较接口也没有重载成成员函数:
5.3、assign()
assign()其实与append()非常相似:

事实上,我们更经常用operator+=,因为方便理解。
5.4、指定位置的插入、删除
插入接口:

string中没有实现头插接口,所以我们只能用insert()。
但是使用insert()进行头插操作,效率是不太高的。(我们在之前的数据结构学习中就知道,包含数组的数据结构,头插是要挪动其他数据的)
删除接口:

5.5、replace()






