第13条:vector与string优先于动态分配的数组
vector和string可以自己管理自己的内存,是功能完全的STL容器,所以凡是适用于序列式容器的算法都可以使用,数组也可以用于STL算法,但是数组没有提供像begin,end及size这样的成员函数,也没有像iterator reverse_iterator和value_type这样的嵌套类型定义。
string一般都使用了引用计数计数,这样可以消除不必要的内存分配和不必要的字符拷贝,从而可以提高很多应用程序的效率,
但如果在多线程环境下使用了这种string,则这所节省下来的时间比不是花在同步控制上的时间。
如果是在多线程环境下,解决string这种计数方式的引起的效率,有三种可行方案:
1)检查库的实现,看看是否有可能禁止引用计数,通常是通过改变某个预处理变量的值,但这种不是可移植的做法,但可以一试
2)寻找或开发一个不使用引用计数的string实现(或者是部分实现)
3)考虑使用vector<char>而不是string,vector的实现不允许使用引用计数,所以不会发生隐藏的多线程性能问题。
总结起来,如果正在动态的分配数组,那么可能会做更多的工作,为了减轻自己的负担,请使用vector或string
第14条 使用reserve来避免不必要的重新分配。
vector和string的重新分配空间的过程:
1)分配一块大小为当前容量的某个倍数的新内存。在大多数实现中,vector和string的容量每次2的倍数增长,即每当容器需要扩容时,它们的容量即加倍。
2)把容器的所有元素从旧的内存复制到新的内存。
3)析构掉旧内存中的对象。
4)释放掉旧内存。
这个过程非常耗时,而且每当这些步骤发生时,vector和string中所有的指针,迭代器和引用都将变得无效。
vector和string中四个容易混淆的函数:
1)size():容器中有多少个元素,但是不是说多少内存
2)capacity():容器李颖已经分配的内存可以容纳多少个元素。这是容器所能容纳的元素总数,而不是还能容纳多少个元素。可以用capacity()-size()得出还有多少未被使用的内存
3)resize(Container::size_type n):强迫容器改变到包含n个元素的状态。在调用resize()后,size()返回n.
如果n比当前的大小(size)要小,则容器尾部的元素将会被析构。
如果n比当前的大小要大,则通过默认构造函数创建的新元素将被添加到容器的末尾。
如果n比当前的容量要大,那么在添加元素之前,将先重新分配内存。
4)reserve(Container::size_type n): 强迫容器把它的容量变为至少是n,前提是n不小于当前的大小。这通常会导致重新分配,因为容量需要增加。
如果n比当前的容量小,
对于vector忽略该调用,什么也不做;对于string,则可能把自己的容量减为size()和n中的最大值,但string的大小肯定保持不变。
但通常,使用reserve从string中除去多余的容量不如使用"swap技巧"
通常有两种方式来使用reserve来避免不必要的重新分配。
第一种:若能确切知道或大致预计容器中最终会有多少元素,则可以使用reserve.
第二种:先预留足够大的空间,然后,把所有数据都加入以后,再去移除多余的容量。