23

C ++ 11では、値パラメーター(およびその他の値)は、返されるときに暗黙的な移動を楽しんでいます。

A func(A a) {
    return a; // uses A::A(A&&) if it exists
}

少なくともMSVC2010では、右辺値参照パラメーターには次のものが必要ですstd::move

A func(A && a) {
    return a; // uses A::A(A const&) even if A::A(A&&) exists
}

内部関数、右辺値参照、および値は同様に動作しますが、値の場合は関数自体が破棄の責任を負い、右辺値参照の場合は外部の責任があるという唯一の違いがあると思います。

標準でそれらを異なる方法で扱う動機は何ですか?

4

3 に答える 3

28

標準化委員会は、移動が正確に 2 つの状況でのみ発生するように、言葉遣いの作成に多大な労力を費やしました。

  1. 明らかに安全である場合。
  2. ユーザーが (または同様のキャストを介して)明示的に要求した場合。std::move

値パラメーターは、関数の最後で間違いなく破棄されます。したがって、move で戻すことは明らかに安全です。リターン後に他のコードが触れることはできません(故意に何かを壊そうとしている場合を除きます。その場合、未定義の動作を引き起こした可能性があります)。そのため、リターンで移動することができます。

&&変数が一時変数を参照している可能性があります。ただし、左辺値 (名前付き変数) を参照している可能性があります。したがって、そこから移動するのは明らかに安全ではありません。元の変数が潜んでいる可能性があります。また、そこから移動することを明示的に要求していない(つまりstd::move、この関数を呼び出していない) ため、移動は行われません。

&&変数が暗黙的に移動されるのは (つまり、 なしでstd::move)唯一の場合は、それを返すときです。std::move<T>を返しますT&&。その戻り値は戻り値であるため、move コンストラクターを呼び出すことは正当です。

現在、呼び出し(または同等のキャスト)なしA func(A &&a)で左辺値を使用して呼び出すことは非常に困難です。したがって、技術的には、タイプのパラメーターを暗黙的に移動しても問題ありません。しかし、標準化委員会は、移動がこの関数のスコープ内で暗黙的に発生しないようにするためだけに、移動が型に対して明示的であることを望んでいました。つまり、 がどこから来たのかについての機能外の知識を使用することはできません。std::move&&&&&&

一般に、パラメーター&&は次の 2 つの場合にのみ使用する必要があります。移動コンストラクター (または移動代入演算子ですが、値によって実行することもできます) を作成する場合と、転送関数を作成する場合です。&&他にもいくつかのケースがあるかもしれませんが、何か特別なことを考えていない限り、型を取るべきではありません。が可動型の場合Aは、値で取得します。

于 2012-03-19T23:21:24.500 に答える
5

あなたの最初のケースでは、コンパイラはそれaがなくなりつつあることを認識しており、それに固執することはできません。明らかに、このオブジェクトは移動でき、そうでない場合は破棄されます。2 番目のケースでは、右辺値参照は、オブジェクトからの移動が許可されていることを示しており、呼び出し元はオブジェクトが留まることを期待していません。ただし、この許可を利用するかどうかは関数の選択であり、関数が引数から移動したい場合と移動したくない場合がある理由がある場合があります。コンパイラがこのオブジェクトから移動する自由を与えられた場合、コンパイラがそうするのを防ぐ方法はありません。ただし、std::move(a)オブジェクトから移動する必要があることを示す方法は既にあります。

標準の一般的な規則は、コンパイラは、消えることがわかっているオブジェクトのみを暗黙的に移動するというものです。右辺値参照が入ってきたとき、コンパイラはオブジェクトが離れようとしていることを実際には知りません: 明示的にstd::move()編集された場合、実際にはそこにとどまります。

于 2012-03-19T23:24:57.170 に答える