この場合
struct Foo {};
Foo meh() {
return std::move(Foo());
}
Foo
新しく作成されるのは xvalue なので、移動は不要であると確信しています。
しかし、このような場合はどうなるのでしょうか?
struct Foo {};
Foo meh() {
Foo foo;
//do something, but knowing that foo can safely be disposed of
//but does the compiler necessarily know it?
//we may have references/pointers to foo. how could the compiler know?
return std::move(foo); //so here the move is needed, right?
}
そこで移転が必要だと思いますか?
ベストアンサー1
return std::move(foo);
の場合、move
12.8/32 のため不要です。
コピー操作の省略の基準が満たされているか、またはソース オブジェクトが関数パラメータであり、コピーされるオブジェクトが lvalue によって指定されているという事実を除いて満たされる場合、オブジェクトが rvalue によって指定されているかのように、コピーのコンストラクターを選択するためのオーバーロード解決が最初に実行されます。
return foo;
は NRVO のケースなので、コピー省略が許可されます。は左辺値です。したがって、 から の戻り値へfoo
の「コピー」に選択されたコンストラクタは、存在する場合は移動コンストラクタである必要があります。foo
meh
しかし、追加するmove
と潜在的な効果があります。それは、移動が省略されるのを防ぐためreturn std::move(foo);
です。ないNRVOの対象となります。
私の知る限り、12.8/32はのみlvalue からのコピーを移動によって置き換えることができる条件。コンパイラは一般に、コピー後に lvalue が未使用であることを検出 (たとえば DFA を使用) して、独自の判断で変更を加えることはできません。ここでは、2 つの間に目に見える違いがあると想定しています。目に見える動作が同じであれば、「as-if」ルールが適用されます。
したがって、タイトルの質問に答えるには、std::move
戻り値を移動したいが、移動されない場合は、戻り値に を使用します。つまり、次のようになります。
- 移動させたい場合、
- それは左辺値であり、
- コピー省略の対象にはならず、
- 値渡し関数パラメータの名前ではありません。
これはかなり面倒で、動きがいつもの安価ですが、テンプレート以外のコードではこれを少し簡略化できると言うかもしれません。次のstd::move
場合に使用します。
- 移動させたい場合、
- それは左辺値であり、
- それについて心配する必要はありません。
簡略化されたルールに従うと、移動省略がいくらか犠牲になります。std::vector
移動コストが安いタイプの場合、おそらく気付かないでしょう (気付いたとしても最適化できます)。std::array
移動コストが高いタイプの場合、または移動コストが安いかどうかわからないテンプレートの場合、そのことを気にする方が面倒です。