既存の回答std::move
では、プログラムをコンパイルするための回避策が提供されていますが、の使用はemplace_back
誤解に基づいているように思われると言わざるを得ません。
あなたがそれを説明する方法(「私は [...] を使用してコンテンツをベクターから別のベクターに移動しようとしていましたemplace_back()
」 )とその使用方法は、要素をベクターに移動emplace_back
する方法として考えていることを示唆しています。の要素をベクターにコピーする方法として。ベクトルの最初のインスタンスを埋めるために使用するコードも、これを示唆しているようです。push_back
std::vector<obj> v;
for( int i = 0; i < 1000; ++i )
{
v.emplace_back(obj("Jon"));
}
しかし、これは と の違いではありませemplace_back
んpush_back
。
まず、push_back
右辺値のみが指定され、要素の型に移動代入演算子がある場合、要素をベクターに移動します (コピーしません) 。
第二に、 の実際の使用例は、emplace_back
要素を所定の位置に構築することです。つまり、まだ存在していないオブジェクトをベクターに入れたい場合に使用します。の引数はemplace_back
、オブジェクトのコンストラクターへの引数です。したがって、上記のループは実際には次のようになります。
std::vector<obj> v;
for( int i = 0; i < 1000; ++i )
{
v.emplace_back("Jon"); // <-- just pass the string "Jon" , not obj("Jon")
}
既存のコードが機能する理由は、それobj("Jon")
がコンストラクター (具体的には移動コンストラクター) への有効な引数でもあるためです。しかし、 の主な考え方はemplace_back
、オブジェクトをobj("Jon")
作成してから移動する必要がないということです。オブジェクトに渡すのではなく、その考え方から恩恵を受けることはありません"Jon"
。
一方、2 番目のループでは、以前に作成されたオブジェクトを扱っています。を使用emplace_back
して既に存在するオブジェクトを移動しても意味がありません。繰り返しemplace_back
ますが、既存のオブジェクトに適用されても、オブジェクトが移動されるわけではありません。これは、通常のコピー コンストラクター (存在する場合) を使用して、その場で作成されることを意味するだけです。移動したい場合は、 を使用push_back
して、 の結果に適用しstd::move
ます。
std::vector<obj> p;
for( int i = 0; i < 1000; ++i )
{
p.push_back(std::move(v[i])); // <-- Use push_back to move existing elements
}
その他の注意事項
1) C++11 の範囲ベースの for を使用して、上記のループを単純化できます。
std::vector<obj> p;
for (auto &&obj : v)
p.push_back(std::move(obj));
2) 通常の for ループを使用するか範囲ベースの for を使用するかに関係なく、要素を 1 つずつ移動します。つまり、ソース ベクトルv
は 1000 個の空のオブジェクトのベクトルとして残ります。プロセスで実際にベクターをクリアしたい場合 (ただし、移動セマンティクスを使用して要素を新しいベクターに転送する場合)、ベクター自体の移動コンストラクターを使用できます。
std::vector<obj> p(std::move(v));
これにより、2 番目のループが 1 行に削減され、ソース ベクターが確実にクリアされます。