C ++ push_back vs Insert vs emplace

时间:2013-02-21 18:16:53

标签: c++ vector insert push-back

我目前正在使用带有C ++的矢量进行应用程序。

我知道预先优化是多么邪恶的根源。

但我真的不禁好奇。

我正在将其他矢量的一部分添加到另一个矢量中 我们会说矢量的大小永远不会改变为300。

因为我总是附加到向量的末尾

做得更快:
a.reserve(300);
a.insert(a.end(), b.begin(), b.end());

或者通过push_backemplace循环遍历我想要追加的向量并单独添加每个项目(同时仍然预先保留)会更快。 (不确定哪个更快)

任何人都可以帮助我吗?

3 个答案:

答案 0 :(得分:9)

这是一个一般原则:当库同时提供do_x_oncedo_x_in_batch时,后者应该至少与在简单循环中调用do_x_once一样快。如果不是,那么库的实现非常糟糕,因为简单的循环足以获得更快的版本。通常,此类批处理函数/方法可以执行其他优化,因为它们具有数据结构内部的知识。

因此,insert应该至少与循环中的push_back一样快。在这种特殊情况下,insert的智能实现可以为要插入的所有元素执行单个reservepush_back每次都必须检查向量的容量。不要试图超越图书馆:)

答案 1 :(得分:4)

正如larsmans所说,你在单一的图书馆电话中做的越多,就越好 更有可能是提高效率。在insert的情况下 在一个向量中,该库通常最多只能做一个 重新分配,并复制每个移位的元素一次。 如果您使用循环和push_back,它可以重新分配几个 时间,这可能会明显变慢(如顺序) 幅度)。

然而,根据类型,它也可能更快 类似的东西:

a.resize( 300 );
std::copy( b.begin(), b.end(), a.end() - 300 );

我发现对于简单的标量类型(如 int)在Intel机器上使用g ++。

答案 2 :(得分:4)

我想这实际上取决于编译器(库实现),编译选项和架构。在英特尔至强中没有优化(/ Od)的情况下在VS2005中进行快速基准测试:

std::vector<int> a;
std::vector<int> b;

// fill 'a' with random values for giggles

timer.start()
// copy values from 'a' to 'b'
timer.stop()

我使用这些不同的“复制值...”方法获得了10 000 000个项目的结果:

  1. 为'b'预留空间,然后使用b.push_back(a[i]); for循环:0.808秒
  2. 调整'b',然后使用索引赋值b[i] = a[i];进行for循环:0.264秒
  3. 没有重新调整'b',仅b.insert(b.end(), a.begin(), a.end());:0.021秒(与预留优先没有显着差异)
  4. std::copy(a.begin(), a.end(), std::back_inserter(b));:0.944秒(先保留0.871)
  5. 调整'b',然后对基本指针memcpy(&(b[0]), &(a[0]), 10000000*sizeof(int));进行memcopy:0.061秒
  6. 然后启用优化(/ Ox),这是一个不同的故事。我不得不将规模增加到100 000 000以获得更多的差异化:

    1. push_back loop:0.659 sec
    2. 索引循环:0.482秒
    3. 插入:0.210秒(与先保留无显着差异)
    4. std :: copy:0.422秒,先保留。没有它就得了一个bad_alloc。
    5. memcpy:0.329秒
    6. 值得注意的是,无论是否进行优化,insert方法都会线性缩放。其他方法在没有优化的情况下显然效率低下,但仍然无法使用它们。正如詹姆斯坎泽所指出的那样,它与g ++不同。使用您自己的平台运行测试以进行验证。