web-dev-qa-db-ja.com

push_backとemplace_back

Push_backemplace_backの違いについて少し混乱しています。

void emplace_back(Type&& _Val);
void Push_back(const Type& _Val);
void Push_back(Type&& _Val);

右辺値参照を取るPush_backオーバーロードがあるので、私はemplace_backの目的が何になるかについてよくわかりませんか?

616
ronag

訪問者が言ったことに加えて:

MSCV10で提供されている関数void emplace_back(Type&& _Val)は、遵守していない冗長なものです。これは、既に述べたように、Push_back(Type&& _Val)と厳密に等価であるためです。

しかし、実際のC++ 0x形式のemplace_backは本当に便利です。 void emplace_back(Args&&...) ;

value_typeをとる代わりに、可変個の引数リストを取るので、引数を完全に転送し、一時的にオブジェクトを作成せずにオブジェクトを直接コンテナに構築できます。

RVOとムーブの意味がどれほど巧妙に表にもたらされても、Push_backが不要なコピーを作成(または移動)する可能性がある複雑なケースがまだあるため、これは便利です。例えば、std::mapの伝統的なinsert()関数では、一時的なものを作成しなければなりません。そして、それは次にstd::pair<Key, Value>にコピーされます。

std::map<int, Complicated> m;
int anInt = 4;
double aDouble = 5.0;
std::string aString = "C++";

// cross your finger so that the optimizer is really good
m.insert(std::make_pair(4, Complicated(anInt, aDouble, aString))); 

// should be easier for the optimizer
m.emplace(4, anInt, aDouble, aString);

では、なぜ彼らはMSVCで正しいバージョンのemplace_backを実装しなかったのでしょうか。実は、それは少し前に私を悩ませたので、 Visual C++ブログ で同じ質問をしました。 MicrosoftのVisual C++標準ライブラリ実装の公式メンテナであるStephan T Lavavejからの回答です。

Q:現在ベータ2のemplace関数は、ある種のプレースホルダーにすぎませんか?

A:ご存知のとおり、可変テンプレートはVC10では実装されていません。 make_shared<T>()、Tuple、<functional>の新しいものなどのプリプロセッサ機構を使ってそれらをシミュレートします。このプリプロセッサ機構は、使用および保守が比較的困難です。また、サブヘッダを繰り返し含める必要があるため、コンパイル速度にも大きく影響します。時間的制約とコンパイル速度の問題の組み合わせのため、emplace関数では可変テンプレートをシミュレートしていません。

可変テンプレートがコンパイラに実装されると、emplace関数を含むライブラリでそれらを利用することが期待できます。我々は非常に真剣に順応をとります、しかし残念なことに、我々はすべてを一度にすることができません。

それは理解できる決定です。さまざまなテンプレートをプリプロセッサで恐ろしいトリックでエミュレートしようとしたことがある人はだれでも、このことがどれほど不快であるかを知っています。

484
Thomas Petit

emplace_backvector::value_type型の引数をとるべきではなく、代わりに追加項目のコンストラクタに転送される可変引数を取るべきです。

template <class... Args> void emplace_back(Args&&... args); 

コピーコンストラクタに転送されるvalue_typeを渡すことは可能です。

それは引数を転送するので、これはあなたが右辺値を持っていないなら、これはまだコンテナが移動されたコピーではなく「コピーされた」コピーを保存することを意味します。

 std::vector<std::string> vec;
 vec.emplace_back(std::string("Hello")); // moves
 std::string s;
 vec.emplace_back(s); //copies

しかし、上記はPush_backがすることと同じであるべきです。それはおそらくむしろ以下のようなユースケースのためのものです。

 std::vector<std::pair<std::string, std::string> > vec;
 vec.emplace_back(std::string("Hello"), std::string("world")); 
 // should end up invoking this constructor:
 //template<class U, class V> pair(U&& x, V&& y);
 //without making any copies of the strings
178
visitor

emplace_backの最適化は次の例で実証できます。

emplace_backコンストラクタの場合、A (int x_arg)が呼び出されます。そしてPush_backの場合、A (int x_arg)が最初に呼び出され、その後move A (A &&rhs)が呼び出されます。

もちろん、コンストラクタはexplicitとしてマークされる必要がありますが、現在の例では明示性を取り除くのに良いです。

#include <iostream>
#include <vector>
class A
{
public:
  A (int x_arg) : x (x_arg) { std::cout << "A (x_arg)\n"; }
  A () { x = 0; std::cout << "A ()\n"; }
  A (const A &rhs) noexcept { x = rhs.x; std::cout << "A (A &)\n"; }
  A (A &&rhs) noexcept { x = rhs.x; std::cout << "A (A &&)\n"; }

private:
  int x;
};

int main ()
{
  {
    std::vector<A> a;
    std::cout << "call emplace_back:\n";
    a.emplace_back (0);
  }
  {
    std::vector<A> a;
    std::cout << "call Push_back:\n";
    a.Push_back (1);
  }
  return 0;
}

出力:

call emplace_back:
A (x_arg)

call Push_back:
A (x_arg)
A (A &&)
58
vadikrobot

emplace_back準拠の実装は、ベクトルに追加されると引数をvector<Object>::value_typeコンストラクタに転送します。私はVisual Studioが可変テンプレートをサポートしていなかったことを思い出します、しかし可変テンプレートではVisual Studio 2013 RCでサポートされるので、私は適合署名が追加されると思います。

emplace_backでは、引数を直接vector<Object>::value_typeコンストラクターに直接転送する場合、厳密に言えば、emplace_back関数のために移動可能またはコピー可能な型は必要ありません。 vector<NonCopyableNonMovableObject>の場合、vector<Object>::value_typeは成長するためにコピー可能または移動可能な型を必要とするので、これは役に立ちません。

しかし note これはstd::map<Key, NonCopyableNonMovableObject>には便利かもしれません、一度エントリをマップに割り当てたら、vectorとは違ってもう移動やコピーをする必要がないので、std::mapを有効に使えます。コピー可能でも移動可能でもないマップ型。

8
Germán Diago

Push_backとemplace_backのためのいいコードがここに示されています。

http://en.cppreference.com/w/cpp/container/vector/emplace_back

移動操作は、emplace_backではなくPush_backで見ることができます。

4
Dharma

リストの場合はもう1つ:

//要素をその場で構築します。
emplace_back( "element");

//新しいオブジェクトを作成してから、引数の値をコピー(または移動)します。 Push_back(explicitDataType {"element"});

4
user3847351