C++ 右辺値参照に関する Artima の記事 ( http://www.artima.com/cppsource/rvalue.html ) には次のような言葉があります。 . これは、名前付き変数から誤って 2 回移動することを防ぐために設計された移動セマンティクスの重要な安全機能です。
このようなダブルムーブが実行できる状況は考えられません。この例を挙げていただけますか?言い換えれば、 のすべてのメンバーがT&&
単なる参照ではなく右辺値参照である場合、何が問題になるのでしょうか?
C++ 右辺値参照に関する Artima の記事 ( http://www.artima.com/cppsource/rvalue.html ) には次のような言葉があります。 . これは、名前付き変数から誤って 2 回移動することを防ぐために設計された移動セマンティクスの重要な安全機能です。
このようなダブルムーブが実行できる状況は考えられません。この例を挙げていただけますか?言い換えれば、 のすべてのメンバーがT&&
単なる参照ではなく右辺値参照である場合、何が問題になるのでしょうか?
次のシナリオを検討してください。
void foo(std::string x) {}
void bar(std::string y) {}
void test(std::string&& str)
{
// to be determined
}
を呼び出しfoo
、str
次にbar
を呼び出しstr
、両方とも同じ値で呼び出します。これを行う最良の方法は次のとおりです。
foo(str); // copy str to x
bar(std::move(str)); // move str to y; we move it because we're done with it
これを行うのは間違いです:
foo(std::move(str)); // move str to x
bar(std::move(str)); // move str to y...er, except now it's empty
最初の移動後、 の値str
は指定されていないためです。
したがって、右辺値参照の設計では、この暗黙的な動きはありません。もしそうなら、上記の最善の方法は機能しませstr
んstd::move(str)
。
私が見る方法は、右辺値参照 x がある場合:
T&& x = ...;
x をパラメーターとして使用して関数を呼び出しました。
f(x)
f が x に損害を与える可能性がある (または「x の所有権を取得する」、または「x を使用した最後のクライアントである」) かどうかを f に伝える必要があります。
これを設計する 1 つの方法は、すべての呼び出しを修飾することです。
f(yours_now(x)) // ok to damage
f(still_mine(x)) // dont damage
非修飾呼び出しを違法にします。
もう 1 つの方法は、1 つの方法をデフォルトにすることです。
また:
f(yours_now(x)) // ok to damage
f(x) // dont damage
また
f(x) // ok to damage
f(still_mine(x)) // dont damage
では、すべての使用を限定するのはかさばりすぎて、既定で 1 つの方法を使用する必要があることに同意する場合、どちらが最適でしょうか? どちらの場合も、誤ってデフォルトを選択した場合のコストを見てみましょう。
最初のケースでは、損傷しても問題ありませんでしたが、誤ってそうではないと言いました。この場合、不要なコピーが作成されたためにパフォーマンスが低下しますが、それ以外は大したことはありません。
2 番目のケースでは、オブジェクトに損傷を与えることは許可されていませんが、私たちは誤ってそれが可能であると言いました。f が返されると x が破損した状態になるため、これによりプログラム内の論理的なバグを検出するのが困難になる可能性がありますが、作成者はそうではないと予想していました。
したがって、最初のケースは、「より安全」であるため選択されたものです。