首页 > 代码库 > 使用reserve来避免不必要的重新分配

使用reserve来避免不必要的重新分配



   关于STL容器,最了不起的一点是,它们会自动增长以便容纳下你放入其中的数据,只要没有超出它们的最大限制就可以。对于vectorstring,增长过程是这样来实现的:每当需要更多空间时,就调用与realloc类似的操作。这一类似于realloc的操作分为4部分:

  1. 分配一块大小为当前容量的某个倍数的新内存。在大多数实现中,vectorstring的容量每次以2的倍数增长,即,每当容器需要扩张时,它们的容量即加倍。

  2. 把容器的所有元素从旧的内存拷贝到新的内存中。

  3. 析构掉旧内存中的对象。

  4. 释放旧内存。

    reserve成员函数能使你把重新分配的次数减少到最低限度,从而避免了重新分配内存和指针/迭代器/引用失效带来的开销。在解释reserve怎样做到这一点之前,我将简单概括一下4个相互关联,但有时会被混淆的成员函数。在标准容器中,只有vectorstring提供了所有这4个函数:

    size()说明了改容器中有多少个元素。它不会告诉你该容器为自己所包含的元素分配了多少内存。

    capacity()说明了改容器利用已经分配的内存可以容纳多少个元素。这是容器所能容纳的元素总数,而不是它还能容纳多少个元素。如果你想知道一个vector由多少为被使用的内存,你就得从capacity()中减去size()。如果sizecapacity返回同样的值,就说明容器中不再有剩余空间了。

    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的大小肯定保持不变。)

    例如:假定想创建一个包含11000之间的值的vector<int>。如果不使用reserve,你可能会这样做:

    vector<int> v;

    for (int i = 1;i <= 1000;++i)

      v.push_back(i);

    该循环在进行过程中将导致210次重新分配。如果使用reserve,如下所示:

    vector<int> v;

    v.reserve(1000);

    for (int i = 1;i <= 1000;++i)

        v.push_back(i);

    则在循环过程中将不会再发生重新分配。

如果想除去多余的容量,请参阅如何有效除去多余的容量