首页 > 代码库 > 使用reserve来避免不必要的重新分配
使用reserve来避免不必要的重新分配
关于STL容器,最了不起的一点是,它们会自动增长以便容纳下你放入其中的数据,只要没有超出它们的最大限制就可以。对于vector和string,增长过程是这样来实现的:每当需要更多空间时,就调用与realloc类似的操作。这一类似于realloc的操作分为4部分:
分配一块大小为当前容量的某个倍数的新内存。在大多数实现中,vector和string的容量每次以2的倍数增长,即,每当容器需要扩张时,它们的容量即加倍。
把容器的所有元素从旧的内存拷贝到新的内存中。
析构掉旧内存中的对象。
释放旧内存。
reserve成员函数能使你把重新分配的次数减少到最低限度,从而避免了重新分配内存和指针/迭代器/引用失效带来的开销。在解释reserve怎样做到这一点之前,我将简单概括一下4个相互关联,但有时会被混淆的成员函数。在标准容器中,只有vector和string提供了所有这4个函数:
size()说明了改容器中有多少个元素。它不会告诉你该容器为自己所包含的元素分配了多少内存。
capacity()说明了改容器利用已经分配的内存可以容纳多少个元素。这是容器所能容纳的元素总数,而不是它还能容纳多少个元素。如果你想知道一个vector由多少为被使用的内存,你就得从capacity()中减去size()。如果size和capacity返回同样的值,就说明容器中不再有剩余空间了。
resize(Container::size_type n)强迫容器改变到包含n个元素的状态。在调用resize之后,size将返回n。如果n比当前的大小要小,则容器尾部的元素将会被析构掉。如果n比当前的大小要大,则通过默认构造函数创建的新元素将被添加到容器的末尾。如果n比当前的容量要大,那么在添加元素之前,将先重新分配内存。
reserve(Container::size_type n)强迫容器把它的容量变为至少是n,前提是n不小于当前的大小。这通常会导致重新分配,因为容量会增加。(如果n比当前的容量小,则vector忽略该调用,什么也不做;而string则可能把自己的容量减为size()和n中的最大值,但是string的大小肯定保持不变。)
例如:假定想创建一个包含1到1000之间的值的vector<int>。如果不使用reserve,你可能会这样做:
vector<int> v;
for (int i = 1;i <= 1000;++i)
v.push_back(i);
该循环在进行过程中将导致2到10次重新分配。如果使用reserve,如下所示:
vector<int> v;
v.reserve(1000);
for (int i = 1;i <= 1000;++i)
v.push_back(i);
则在循环过程中将不会再发生重新分配。
如果想除去多余的容量,请参阅如何有效除去多余的容量