std :: vector :: reserve性能惩罚

时间:2009-11-16 15:23:05

标签: c++ performance stl stdvector

inline void add(const DataStruct& rhs) {
   using namespace boost::assign;
   vec.reserve(vec.size() + 3);
   vec += rhs.a, rhs.b, rhs.c;
}

上面的函数执行了大约17000次,并且执行了(据我所知。有一些转换)大约2个数量级更强 调用vector :: reserve。

我一直认为保留可以加速push_back,即使是小值,但这似乎不正确,我找不到任何明显的原因,为什么它不应该这样。保留是否会阻止功能的内联?对size()的调用是否过于昂贵?这取决于平台吗?我会尝试编写一些小基准来在干净的环境中确认这一点。

编译器:gcc (GCC) 4.4.2,带-g -O2

6 个答案:

答案 0 :(得分:24)

reserve()的GCC实现将分配确切数量的元素,而push_back()将通过加倍来指数增长内部缓冲区,因此您正在击败指数增长并在每次迭代时强制重新分配/复制。在ltracevalgrind下运行测试,查看malloc()来电的数量。

答案 1 :(得分:7)

如果您事先知道元素的数量,则只能使用reserve()。在这种情况下,reserve()空间同时为所有元素。

否则只需使用push_back()并依赖默认策略 - 它将以指数方式重新分配,并以稍微不理想的内存消耗为代价大大减少重新分配的数量。

答案 2 :(得分:6)

如果您事先知道将使用多少地方,请仅使用保留。

预约将需要复制整个矢量......

如果你执行push_back并且向量太小,那么它将执行保留(vec.size()* 2)。

如果你事先不知道你的矢量有多大,如果你需要随机访问,可以考虑使用std :: deque。

答案 3 :(得分:4)

当std :: vector需要重新分配时,它的分配大小增加N * 2,其中n是其当前大小。随着向量的增长,这会导致对数的realloc。

如果相反,std :: vector以恒定量增加其分配的空间,则reallocs的数量将随着向量的增长而线性增长。

你所做的实际上是导致矢量以恒定量3增长,这意味着线性增长。线性显然比对数更差,特别是对于大数字。

通常,唯一比对数增长更好的增长是不变的。这就是标准委员会创建储备方法的原因。如果你可以避免所有reallocs(常量),你将比默认的对数行为表现更好。

那说你可能想要考虑一下Herb Sutter关于更喜欢std :: deque而不是vector www.gotw.ca/gotw/054.htm

的评论

答案 4 :(得分:3)

将保留区移到添加区外。

每次调用“add”时,都会保留至少3个额外元素。根据vector的实现,几乎每次调用“add”时,都可能增加后备数组的大小。这肯定会导致你描述的性能差异。

使用保留的正确方法如下:

vec.reserve(max*3);
for(int i=0; i<max; i++)
   add(i);

答案 5 :(得分:3)

如果您对我打赌的代码进行了分析,您会发现+ = IS非常快,问题就在于储备正在扼杀您。当你对向量增长到多大有所了解时,你应该只使用reserve。如果您可以提前猜测,那么请执行一次预留,否则只需使用默认的push_back。