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
答案 0 :(得分:24)
reserve()
的GCC实现将分配确切数量的元素,而push_back()
将通过加倍来指数增长内部缓冲区,因此您正在击败指数增长并在每次迭代时强制重新分配/复制。在ltrace
或valgrind
下运行测试,查看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。