在向量中使用reserve()的好处 - C ++

时间:2011-06-29 18:46:58

标签: c++ performance vector

在处理向量时使用reserve有什么好处。我应该什么时候使用它们?无法找到明确的答案,但我认为在使用之前提前预订会更快。

你说人比我更聪明?

7 个答案:

答案 0 :(得分:27)

如果您知道向量最终将保留多少元素,这将非常有用 - 它可以帮助向量避免重复分配内存(并且必须将数据移动到新内存中)。

一般情况下,这可能是一个你不应该担心的潜在优化,但它也没有害处(最糟糕的是,如果过度估计,你最终会浪费内存)。

当您想要确保现有迭代器不会因添加新元素而失效时,可能不仅仅是优化的一个领域。

例如,push_back()调用可能使向量的现有迭代器无效(如果发生重新分配)。但是,如果您预留了足够的元素,则可以确保不会发生重新分配。这是一种不需要经常使用的技术。

答案 1 :(得分:7)

它可能是......特别是如果你要随着时间的推移向你添加很多元素,你想要避免容器在可用插槽用完时自动进行内存扩展。 / p>

例如,反向插入(即std::vector::push_back)被认为是 ammortized O(1)或常量时间进程,但这是因为如果在后面插入制作一个向量,并且向量超出空间,然后必须为新的元素数组重新分配内存,将旧元素复制到新数组中,然后它可以复制您尝试插入到容器中的元素。该过程是O(N)或线性时间复杂度,对于大矢量,可能需要相当长的时间。使用reserve()方法允许您为向量预先分配内存,如果您知道它将至少具有某个特定大小,并避免每次空间耗尽时重新分配内存,特别是如果您要回来 - 在一些性能关键代码中插入,您希望确保插入时间仍然是实际的O(1)复杂性过程,并且不会导致数组的某些隐藏内存重新分配。当然,你的复制构造函数也必须是O(1)复杂度才能获得整个反向插入过程的真实O(1)复杂度,但是关于容器本身向后插入向量的实际算法如果插槽的内存已经预分配,则可以保持已知的复杂性。

答案 2 :(得分:7)

This excellent article深刻解释了dequevector容器之间的差异。 “实验2”部分显示了vector::reserve()的好处。

答案 3 :(得分:3)

如果您知道矢量的最终大小,则保留值得使用。

否则每当向量用完内部空间时,它将重新调整缓冲区的大小。这通常涉及内部缓冲区大小加倍(或1.5 *当前大小)(如果你这么做的话,可能会很昂贵)。

真正昂贵的一点是调用每个元素上的复制构造函数将其从旧缓冲区复制到新缓冲区,然后在旧缓冲区中的每个元素上调用析构函数。

如果复制构造函数很昂贵,那么它可能是个问题。

答案 4 :(得分:1)

更快并节省内存

如果你push_back另一个元素,那么一个完整的向量通常会分配它当前正在使用的内存的两倍 - 因为allocate + copy是昂贵的

答案 5 :(得分:1)

不要知道比你更聪明的人,但我会说如果你要在插入操作中执行很多并且你已经知道或可以估计元素的总数,你应该提前致电reserve ,至少是数量级。它可以在良好的环境中为您节省大量的重新分配。

答案 6 :(得分:0)

虽然这是一个老问题,但这是我对差异的实施。

#include <iostream>
#include <chrono>
#include <vector>

using namespace std;

int main(){
    vector<int> v1;
    chrono::steady_clock::time_point t1 = chrono::steady_clock::now();
    for(int i = 0; i < 1000000; ++i){
        v1.push_back(1);
    }
    chrono::steady_clock::time_point t2 = chrono::steady_clock::now();
    chrono::duration<double> time_first = chrono::duration_cast<chrono::duration<double>>(t2-t1);
    cout << "Time for 1000000 insertion without reserve: " << time_first.count() * 1000 << " miliseconds." << endl;

    vector<int> v2;
    v2.reserve(1000000);
    chrono::steady_clock::time_point t3 = chrono::steady_clock::now();
    for(int i = 0; i < 1000000; ++i){
        v2.push_back(1);
    }
    chrono::steady_clock::time_point t4 = chrono::steady_clock::now();
    chrono::duration<double> time_second = chrono::duration_cast<chrono::duration<double>>(t4-t3);
    cout << "Time for 1000000 insertion with reserve: " << time_second.count() * 1000 << " miliseconds." << endl;
    return 0;
}

编译并运行此程序时,它会输出:

Time for 1000000 insertion without reserve: 24.5573 miliseconds.

Time for 1000000 insertion with reserve: 17.1771 miliseconds.

似乎在保留方面有所改善,但并没有那么多改进。我认为对复杂的物体来说会有更多的改进,我不确定。欢迎任何建议,变更和评论。