14

オブジェクトを値で関数に渡すとき、コピーの省略がないと仮定して、移動コンストラクターがあれば常に呼び出されることを私は知っています。オブジェクトを値で返すのはどうですか?

たとえばFoo、move コンストラクタを持つクラスがあり、オブジェクトを返す関数があるとしFooます。

Foo g() {
    Foo f;

    // do something with f

    return f;
}

RVO がないと仮定すると、move コンストラクターが呼び出されることが保証されますか?

更新: 意図を明確に示さなかったと思います。最悪の場合、オブジェクトをコピーせずに移動できることを知りたいだけです。RVO か NRVO のいずれかが発生し、私は満足しています。また、move コンストラクターと move 代入は削除されておらず、適切に実装されているとも言えます。

4

3 に答える 3

8

はい。[class.copy] p32 を参照

コピー操作の省略の基準が満たされているか、ソース オブジェクトが関数パラメーターであり、コピーされるオブジェクトが左辺値によって指定されているという事実を除いて満たされる場合、コピーのコンストラクターを選択するためのオーバーロードの解決は次のとおりです。オブジェクトが右辺値によって指定されたかのように最初に実行されます。オーバーロードの解決が失敗した場合、または選択されたコンストラクターの最初のパラメーターの型がオブジェクトの型 (おそらく cv 修飾) への右辺値参照でない場合、オブジェクトを左辺値と見なしてオーバーロードの解決が再度実行されます。[注:この 2 段階のオーバーロード解決は、コピーの省略が発生するかどうかに関係なく実行する必要があります。省略が実行されない場合に呼び出されるコンストラクターを決定し、呼び出しが省略された場合でも、選択されたコンストラクターにアクセスできる必要があります。—エンドノート]

于 2012-06-18T18:06:16.957 に答える
2

ルールは、コピー省略が許可されているが発生しない場合は常に、使用可能な場合は移動コンストラクターが使用され、そうでない場合はコピー コンストラクターが使用されるというものです。

正確な動作は次のように定義され[class.copy]/32ます:

コピー操作の省略の基準が満たされているか、ソース オブジェクトが関数パラメーターであり、コピーされるオブジェクトが左辺値によって指定されているという事実を除いて満たされる場合、コピーのコンストラクターを選択するためのオーバーロードの解決は次のとおりです。オブジェクトが右辺値によって指定されたかのように最初に実行されます。オーバーロードの解決が失敗した場合、または選択されたコンストラクターの最初のパラメーターの型がオブジェクトの型 (おそらく cv 修飾) への右辺値参照でない場合、オブジェクトを左辺値と見なしてオーバーロードの解決が再度実行されます。

于 2012-06-18T17:52:18.970 に答える
2

この場合、戻り値には名前 ( f) があるため、適用されるのは NRVO (名前付き戻り値の最適化) になります。

したがって、文言のみに基づく技術的な答えは、RVO がなくてもコピーの省略を防ぐことはできないということです。

それを過ぎると、戻り値の移動/コピーの選択は Foo の定義に依存する可能性がある/依存することになると思います-移動コンストラクターを明示的に削除した場合など、移動する代わりにコピーされることが間違いなくあります代入演算子を移動するか、移動の構築/代入を定義していないため、それらを暗黙的に合成する資格がありません。

編集: [編集された質問への回答]: 移動コンストラクターを使用しても、結果が移動されることは保証されません。明らかな例の 1 つは、move 代入演算子を削除し、(初期化に使用するのではなく) 結果を代入していた場合です。この場合、削除された移動代入演算子は、戻り値の移動を妨げます。

ただし、あなたが得ているかもしれないことに答えるために、一般的なルールは、可能であれば移動が行われ、何かが結果の移動を妨げる場合にのみ、コピーにフォールバックするということです。

于 2012-06-18T17:47:25.127 に答える