emplace_back が push_back より速いのはなぜですか? 質問する

emplace_back が push_back より速いのはなぜですか? 質問する

emplace_back次のようなことをしたとき、それが勝者になるだろうと思いました。

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

emplace_backオブジェクトをすぐにベクトル内に構築しますが、 はpush_back最初に匿名オブジェクトを構築してからそれをベクトルにコピーします。詳細については、これ質問。

Googleはまた、これそしてこれ質問。

私は整数で満たされるベクトルについてそれらを比較することにしました。

実験コードは次のとおりです。

#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.

なぜでしょうか? 最初にリンクされた質問の回答では、パフォーマンスの違いはないと明確に述べられています。

他のものも試してみた時間メソッド、しかし、同じ結果が得られました。

[編集] コメントによると、ints を使用したテストでは何も行われず、push_backref が必要になるとのことです。

上記のコードで同じテストを実行しましたが、代わりにintクラスを使用しました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.

[編集.2]

denlan さんが言ったように、操作の位置も変更する必要があるため、操作を入れ替えて、両方の状況 (intおよびclass A)でemplace_back再び勝者になりました。

[解決]

コードを で実行していたdebug modeため、測定値が無効になりました。ベンチマークの場合は、常に でコードを実行してくださいrelease mode

ベストアンサー1

テスト ケースはあまり役に立ちません。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

emplace_backしかし、重要な違いは、明示的な変換:

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

この例は、将来的には と言うべきで、少し不自然になります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)

おすすめ記事