web-dev-qa-db-ja.com

すでに構築されたオブジェクトに対するstd :: moveとemplace_back()を使用したC ++ 11 Push_back()の効率

C++ 11では、emplace_back()はインプレース構造を可能にするため、Push_back()よりも(効率の点で)一般的に好まれますしかし、Push_back(std::move())既に構築されたオブジェクトを使用していますか?

たとえば、次のような場合にemplace_back()はまだ好まれますか?

std::string mystring("hello world");
std::vector<std::string> myvector;

myvector.emplace_back(mystring);
myvector.Push_back(std::move(mystring));
// (of course assuming we don't care about using the value of mystring after)

さらに、上記の例に代わりに行うメリットがあります:

myvector.emplace_back(std::move(mystring));

または、ここでの移動は完全に冗長ですか、それとも効果はありませんか?

76
Riot

あなたが提供したさまざまな呼び出しが何をするのか見てみましょう:

  1. emplace_back(mystring):これは、指定した引数を使用した新しい要素のインプレース構築です。あなたは左辺値を提供したので、そのインプレース構造は実際にはコピー構造です。つまり、これはPush_back(mystring)を呼び出すことと同じです。

  2. Push_back(std::move(mystring)):これは、move-insertionを呼び出します。std:: stringの場合、in-place move-constructionです。

  3. emplace_back(std::move(mystring)):これも、指定した引数を使用したインプレース構造です。その引数は右辺値であるため、_std::string_のmove-constructorを呼び出します。つまり、2のようなインプレースmove-constructionです。

つまり、型Tの1つの引数で呼び出された場合、右辺値でも左辺値でも、_emplace_back_と_Push_back_は同等です。

ただし、他の引数の場合、たとえば_emplace_back_が_char const*_で_vector<string>_を使用して、レースに勝ちます。

  1. emplace_back("foo")は、インプレース構築のためにstring::string(char const*)を呼び出します。

  2. Push_back("foo")は、関数のシグネチャと一致するために必要な暗黙の変換のために最初にstring::string(char const*)を呼び出し、次に上記のケース2のような移動挿入を行う必要があります。したがって、Push_back(string("foo"))と同等です

104
Arne Mertz

Emplace_backは右辺値参照のリストを取得し、直接所定の場所にコンテナ要素を構築しようとします。コンテナー要素コンストラクターがサポートするすべてのタイプでemplace_backを呼び出すことができます。右辺値参照ではないパラメーターに対してemplace_backを呼び出すと、通常の参照に「フォールバック」し、パラメーターとコンテナー要素が同じタイプの場合、少なくともコピーコンストラクターが呼び出されます。あなたの場合、「myvector.emplace_back(mystring)」は、パラメーターmyvectorが移動可能であることをコンパイラーが認識できなかったため、文字列のコピーを作成する必要があります。したがって、std :: moveを挿入すると、目的の利点が得られます。 Push_backは、すでに構築された要素のemplace_backと同様に機能するはずです。

1
Tunichtgut