为什么 emplace_back 比 push_back 快? [英] Why emplace_back is faster than push_back?

查看:26
本文介绍了为什么 emplace_back 比 push_back 快?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我认为 emplace_back 会是赢家,当做这样的事情时:

I thought that emplace_back would be the winner, when doing something like this:

v.push_back(myClass(arg1, arg2));

因为 emplace_back 会立即在向量中构造对象,而 push_back 会先构造一个匿名对象,然后将其复制到向量中.如需了解详情,请参阅这个问题.

because emplace_back would construct the object immediately in the vector, while push_back, would first construct an anonymous object and then would copy it to the vector. For more see this question.

Google 还提供了这个这个问题.

Google also gives this and this questions.

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

I decided to compare them for a vector that would be filled by integers.

这是实验代码:

#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;
}

结果是 emplace_back 更快.​​

push_back took me 2.76127 seconds.
emplace_back took me 1.99151 seconds.

为什么?第一个链接问题的答案明确表示不会有性能差异.

Why? The answer of the 1st linked question clearly says that there will be no performance difference.

还尝试了其他时间方法,但得到了相同的结果.

Also tried with other time methods, but got identical results.

评论说用 ints 测试什么也没说,push_back 需要一个引用.

Comments say that testing with ints doesn't say anything and that push_back takes a ref.

我在上面的代码中做了同样的测试,但不是 int 我有一个类 A:

I did the same test in the code above, but instead of int I had a class A:

class A {
 public:
  A(int a) : a(a) {}
 private:
  int a;
};

结果:

push_back took me 6.92313 seconds.
emplace_back took me 6.1815 seconds.

正如denlan所说,我也应该改变操作的位置,所以我交换了它们,在两种情况下(intclass A),emplace_back 再次成为赢家.

As denlan said, I should also change the position of the operations, so I swapped them and in both situation (int and class A), emplace_back was again the winner.

[解决方案]

我在调试模式下运行代码,这使得测量无效.对于基准测试,始终以发布模式运行代码.

I was running the code in debug mode, which makes the measurements invalid. For benchmarking, always run the code in release mode.

推荐答案

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

Your test case isn't very helpful. push_back takes a container element and copies/moves it into the container. emplace_back takes arbitrary arguments and constructs from those a new container element. But if you pass a single argument that's already of element type to emplace_back, you'll just use the copy/move constructor anyway.

这里有一个更好的比较:

Here's a better comparison:

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

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

The key difference, however, is that emplace_back performs explicit conversions:

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

这个例子将来会有点做作,当你应该说v.push_back(std::make_unique(1, 'x', true))时.但是,emplace 的其他结构也非常好:

This example will be mildly contrived in the future, when you should say v.push_back(std::make_unique<Foo>(1, 'x', true)). However, other constructions are very nice with emplace, too:

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)

这篇关于为什么 emplace_back 比 push_back 快?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆