C++ push_back vs Insert vs emplace

C++ push_back vs Insert vs emplace

本文关键字:vs Insert emplace back push C++      更新时间:2023-10-16

我目前正在用C++制作一个使用向量的应用程序。

我知道预优化是万恶之源。

但我真的忍不住好奇。

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

由于我总是将附加到矢量的末尾

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

或者循环通过我想要附加的向量并用CCD_ 3或CCD_。(不确定哪个更快)

有人能帮我吗?

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

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

我想这实际上取决于编译器(库实现)、编译选项和体系结构。在没有优化(/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()

我使用这些不同的"复制值…"方法得到了10000个项目的结果:

  1. 为"b"保留空间,然后使用b.push_back(a[i]);为循环保留空间:0.808秒
  2. 调整"b"的大小,然后对于使用索引分配的循环b[i] = a[i];: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));:0.061秒上进行memcopy

然而,启用了优化(/Ox),情况就不同了。我不得不将尺寸增加到100000 000以获得更多差异化:

  1. push_back循环:0.659秒
  2. 索引循环:0.482秒
  3. 插入时间:0.210秒(与先保留时间无显著差异)
  4. std::复制:0.422秒,先保留。没有它就有一个坏家伙
  5. 记忆时间:0.329秒

值得注意的是,无论是否进行优化,insert方法都是线性缩放的。其他方法在没有优化的情况下显然效率低下,但使用它们仍然无法达到很快的速度。正如詹姆斯·坎泽所指出的,g++上的情况有所不同。使用您自己的平台运行测试以进行验证。

正如larsmans所说,在单个库调用中执行的操作越多它更有可能更有效率。在insert的情况下到一个向量中,库通常最多只做一个重新分配以及最多复制一次每个移位的元素。如果使用循环和push_back,它可以重新分配几个时间,可能会慢得多(比如幅度)。

然而,根据类型的不同,它也可能更快类似于:

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

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