向量插入vs push_back性能问题

时间:2014-12-08 14:12:35

标签: c++ vector stl insert push-back

当我描述我的程序时,我发现了一个瓶颈:

for (int i = 0; i < len; ++i) {
    vec->push_back(buffer[i]);
}

for循环位于一个被称为100k次的函数中。 在用以下代码替换它之后,性能提升是巨大的。 (上面的代码占总时间的10%。下面的代码占0.34%)

vec->insert(vec->end(), buffer, buffer + len);

有问题的矢量具有以下类型:vector<char>* vec

有人能说清楚为什么第二个版本要快得多吗?

我也试过在第一个版本中保留空间,但没有可观察到的改进。

2 个答案:

答案 0 :(得分:1)

如果没有大量数据,很难明确地说明为什么一段非平凡代码执行速度比另一篇快得多,尤其是涉及第三方代码时(在这种情况下是内部vector代码)。但你通常可以做一些猜测。

由于你提到reserve提前没有任何区别,我的猜测是它只是归结为所需的操作次数。在原始代码中,作为第一个近似值,lenbuffer调用len * push_back索引操作始终存在insert ,以及运行循环的一些开销。但是,对push_back的调用不一定如此。该函数的简单实现可能只是在整个范围内遍历迭代器并为每个值调用len,在这种情况下,您可能会看到大致相同的性能。但是,更精明的实现可能会意识到操作归结为复制单个连续的insert字节运行并使用机器指令可以有效地将其作为单个操作实现(可能在调整大小/复制之前)初始缓冲区大小太小)。但唯一可以确定的方法是查看所涉及的实际标准库和/或机器代码。

你没有提到你正在使用的编译器,但仅仅是为了它的实施,我在VS2012中实现了类似你的代码并跟踪了它。memmove最终使用了对{{push_back的单个调用。 1}}执行复制。


* 这是一个近似值,因为如果将{{1}}实现为内联函数,您的编译器设置允许它内联,优化器可能有那个循环的一天。当我说在没有大量具体数据的情况下关于性能的推理可能会很棘手的时候,这就是我所得到的。

答案 1 :(得分:-1)

Vector使用数组作为其底层存储。所以,它会自动完成 在到达数组末尾之前,将数组大小扩展2倍 使用像push_back这样的方法。

但是在插入的情况下,vector会为插入准备足够的存储空间,因为vector知道将插入多少个元素。 这意味着只发生一次扩展。