std::vector::emplace_back
とstd::move
を一緒に使用する利点はありますか?または、std::vector::emplace_back
がインプレース構築を行うため、冗長です。
説明のためのケース:
std::vector<std::string> bar;
最初:
bar.emplace_back(std::move(std::string("some_string")));
2番目:
std::string str("some_string");
bar.emplace_back(std::move(str));
番目:
bar.emplace_back(std::move("some_string"));
2番目のバージョンでは、利点があります。 emplace_back
を使用すると、std::string
のmoveコンストラクターが呼び出され、std::move
を使用するとコピーを保存できます(その文字列がSSOバッファーに格納されていない場合)。これは、この場合のPush_back
と本質的に同じであることに注意してください。
文字列はすでにprvalueであるため、最初のバージョンのstd::move
は不要です。
文字列リテラルは移動できないため、3番目のバージョンのstd::move
は無関係です。
最も単純で最も効率的な方法は次のとおりです。
bar.emplace_back("some_string");
リテラルはコンストラクタに完全に転送されるため、不要なstd::string
構成は必要ありません。
emplace_back
のような呼び出し
new (data+size) T(std::forward<Args>(args)...);
args
が基本-右辺値を参照しないstd::string
の場合、式は次のようにコンパイルされます
new (data+size) std::string(str); //str is lvalue - calls std::string::string(const string& rhs)
コピーコンストラクタが行われることを意味します。ただし、str
でstd::move
を使用すると、コードは次のようにコンパイルされます。
new (data+size) std::string(str); //str is r-value reference, calls std::string::string(string&& rhs)
したがって、移動セマンティクスが行われます。これは大きなパフォーマンスの向上です。
注意してください。str
は左辺値であり、名前が付いているため、そこからr値参照を作成するには、std::move
を使用する必要があります。
例では
vec.emplace_back("some literal");
コードはコンパイルされます
new (data+size) std::string("literal"); //calls std::string::string(const char*);
一時的なものはありません。
3番目の例はナンセンスです。リテラルを移動することはできません。
emplace_back
の全体的な考え方は、コピーおよび移動操作を取り除くことです。 std::string
の入力パラメーターをemplace_back
に渡すだけです。 std::string
オブジェクトは、emplace_back
メソッド内で構築されます。
bar.emplace_back("some_string");
すでに文字列がある場合は、std::move
を使用するのが理にかなっています。 str
からデータを移動することにより、std::string
オブジェクトがemplace_back
内に構築されます。
std::string str("some_string");
bar.emplace_back(std::move(str));
2番目のケースではそうする意味があります。このコードを考えてみましょう:
int main()
{
std::vector<std::string> bar;
std::string str("some_string");
bar.emplace_back(std::move(str)); str.clear();
// bar.emplace_back(str);
std::cout << str << std::endl;
}
コメントを上の行に変更すると、「some_string」の2つのコピー(bar
に1つとstr
に1つ)が作成されることがわかります。だからそれは何かを変えます。
それ以外の場合、1つ目は一時ファイルを移動し、3つ目は定数文字列リテラルを移動します。それは何もしません。