为什么emplace_back比push_back更快?

gsa*_*ras 37 c++ performance stl push-back emplace

emplace_back做以下事情时,我认为这将是胜利者:

v.push_back(myClass(arg1, arg2));
Run Code Online (Sandbox Code Playgroud)

因为emplace_back会在向量中立即构造对象,而push_back首先会构造一个匿名对象,然后将其复制到向量中.有关更多信息,请参阅

谷歌也提出了这个这个问题.

我决定将它们与一个由整数填充的向量进行比较.

这是实验代码:

#include <iostream>
#include <vector>
#include <ctime>
#include <ratio>
#include <chrono>

using namespace std;
using namespace std::chrono;

int main() {

  vector<int> v1;

  const size_t N = 100000000;

  high_resolution_clock::time_point t1 = high_resolution_clock::now();
  for(size_t i = 0; i < N; ++i)
    v1.push_back(i);
  high_resolution_clock::time_point t2 = high_resolution_clock::now();

  duration<double> time_span = duration_cast<duration<double>>(t2 - t1);

  std::cout << "push_back took me " << time_span.count() << " seconds.";
  std::cout << std::endl;

  vector<int> v2;

  t1 = high_resolution_clock::now();
  for(size_t i = 0; i < N; ++i)
    v2.emplace_back(i);
  t2 = high_resolution_clock::now();
  time_span = duration_cast<duration<double>>(t2 - t1);
  std::cout << "emplace_back took me " << time_span.count() << " seconds.";
  std::cout << std::endl;

  return 0;
}
Run Code Online (Sandbox Code Playgroud)

结果emplace_back是更快.

push_back took me 2.76127 seconds.
emplace_back took me 1.99151 seconds.
Run Code Online (Sandbox Code Playgroud)

为什么?第一个相关问题的答案清楚地表明,没有性能差异.

还尝试了我的pesudo网站的其他时间方法,但结果相同.

[编辑]评论说用ints 测试没有说什么,push_back需要参考.

我在上面的代码中做了相同的测试,但int我没有上课A:

class A {
 public:
  A(int a) : a(a) {}
 private:
  int a;
};
Run Code Online (Sandbox Code Playgroud)

结果:

push_back took me 6.92313 seconds.
emplace_back took me 6.1815 seconds.
Run Code Online (Sandbox Code Playgroud)

[EDIT.2]

正如丹兰所说,我也应该改变操作的位置,所以我交换它们,在这两种情况下(intclass A),emplace_back再次成为胜利者.

[解]

我正在运行代码debug mode,这使得测量无效.对于基准测试,请始终运行代码release mode.

Ker*_* SB 50

您的测试用例不是很有帮助.push_back获取容器元素并将其复制/移动到容器中.emplace_back从那些新的容器元素中获取任意参数和构造.但是如果你传递一个已经是元素类型的参数emplace_back,那么你只需要使用复制/移动构造函数.

这是一个更好的比较:

Foo x; Bar y; Zip z;

v.push_back(T(x, y, z));  // make temporary, push it back
v.emplace_back(x, y, z);  // no temporary, directly construct T(x, y, z) in place
Run Code Online (Sandbox Code Playgroud)

然而,关键的区别在于emplace_back执行显式转换:

std::vector<std::unique_ptr<Foo>> v;
v.emplace_back(new Foo(1, 'x', true));  // constructor is explicit!
Run Code Online (Sandbox Code Playgroud)

你应该说,这个例子将来会有轻微的设计v.push_back(std::make_unique<Foo>(1, 'x', true)).但是,其他结构也非常好用emplace:

std::vector<std::thread> threads;
threads.emplace_back(do_work, 10, "foo");    // call do_work(10, "foo")
threads.emplace_back(&Foo::g, x, 20, false);  // call x.g(20, false)
Run Code Online (Sandbox Code Playgroud)