所有STL容器都是有用的,但大多数C++程序员会发现使用vector和string的时候更多一些。设计vector和string的目的就是为了代替在大多数应用中使用的数组。
13. vector和string优先于动态分配的数组。
每当发现需要动态分配一个数组时(如想写new T[……]时),都应该考虑用vector 和string来代替。因为vector和string自己管理内存。
14.使用reserve来避免不必要的内存分配。
STL容器内存增加的流程:
1.分配一块大小为当前容量某个倍数的新内存,在大多数实现中,vector和string的容量每次都以2的倍数增长。
2.把容器所有元素从旧的内存拷贝到新的内存中。
3.析构掉旧内存中的对象。
4.释放旧内存。
每当这些步骤发生的时候,vector和string中所有的指针,迭代器和引用都将变得无效。
避免重新内存分配的关键在于尽早的使用reserve,最好是容器刚被构造出来之后就使用reserve。
如下面代码所示:在循环过程中,内存不会发生重新分配。
vector<int> v;
v.reserve(1000);
for(int i = 1; i <= 1000; ++i)
v.push_back(i);
或者下面的代码, push_back()不会使string的迭代器,指针和引用无效。
string s;
……
if(s.size() < s.capacity())
s.push_back('x');
总之,两种解决方法,若能切确知道或者大致估计容器最终会有多少元素,可以使用reverse,第二种方法是先预留足够大的空间, 当把所有数据都加入以后,在去除多余的容量。
15.注意string实现的多样性。
实现string的方法非常的多。
16.了解如何把vector和string数据传给旧的API。
旧的C API还存在,它们使用数组和char*指针来进行数据交换而不是vector或者string对象。
解决方法:如果有一个vector v,需要得到一个指向v中数据的指针,直接使用&v[0],而对于string s,则对应的形式是s.c_str()。
&v[0]是指向第一个元素的指针。如有这样的一个函数接口:
void doSomething(const int* pInts,size_t numInts)
if(v.empty())
{
doSomething(&v[0],v.size());
}
而如果采用s.c_str()的话,不需要考虑字符串长度是否为0,在这种情况下,c_str()会返回一个空字符的指针。
c_str()返回的指针不可以被修改,返回的类型是const char*类型的指针。如果修改可以用const_cast<char*>(s.c_str)。
如果是其他容器,可以先把容器中的元素拷贝到vector中,然后再传给该C API。当然,C API里的数据也可以通过vector进行中转传给其他STL容器中。
17.使用"swap"技巧除去多余的容量。
vector<int> (v).swap(v);
string (s).swap(s);
C++11新标准有shrink_to_fit函数。
18.避免使用vector<bool>。
作为一个STL容器,vector<bool>只有两点不对,首先它不是一个STL容器,其次它并不存储bool。
标准库提供了两种选择。
第一种是使用deque<bool>,deque几乎提供了vector提供的一切(可以看到的省略只有capacity()和reserve()),但deque<bool>是一个STL容器,它也确确实实存储bool。当然deque的元素内存不是连续的,所以不能把deque<bool>传递给一个期望bool数组的C API。(也不能通过vector进行中间转换。)
第二种是采用bitset。