web-dev-qa-db-ja.com

C ++ 11に&&があるときにstd :: moveを使用するのはなぜですか?

可能性のある複製:
誰かにムーブのセマンティクスを説明してもらえますか?

私は最近C++ 11セミナーに参加しましたが、次のちょっとしたアドバイスがありました。

when you have && and you are unsure, you will almost always use std::move

std::moveいくつかの選択肢とは対照的に、いくつかのケースではstd::move

58
pyCthon

まず、対処する質問に誤解がある可能性があります。
コードに_T&& t_が表示される場合(およびTはテンプレート型ではなく実際の型です)、tの値カテゴリは左辺値(参照)ではなく、もう右辺値(一時)。とてもわかりにくいです。 _T&&_は、単にtが右辺値であったオブジェクトからconstructedであることを意味します 1、ただしtitselfは右辺値ではなく左辺値です。名前(この場合、t)がある場合、それは左辺値であり、自動的に移動しませんが、名前がない場合(_3+4_の結果)、右辺値であり、 自動的に可能な場合、結果に移動します。 type(この場合_T&&_)は、変数の値カテゴリ(この場合は左辺値)とはほとんど関係ありません。

つまり、コードに_T&& t_が記述されている場合は、was一時変数である変数への参照があり、必要に応じて破棄してもかまいません。変数に複数回アクセスする必要がある場合、notその変数から_std::move_する必要があります。そうしないと、値が失われます。ただし、最後にtにアクセスするときは、_std::move_を使用しても安全です。必要に応じて、別のTに値を設定します。 (そして、95%の時間、それはあなたがしたいことです)。これはすべて_auto&&_変数にも適用されます。

1. Tがテンプレート型の場合、_T&&_は代わりに転送参照です。この場合、最後にstd::forward<T>(t)の代わりにstd::move(t)を使用します。 この質問 を参照してください。

85
Mooing Duck

この記事 は、一般に右辺値参照の主題についてかなり啓発的であることがわかりました。彼は最後に向かってstd::moveに言及しています。これはおそらく最も関連する引用です:

std::moveからの<utility>を使用する必要があります-std::moveは「OK 」 std::moveは、それ自体は何も移動しません。移動コンストラクターを呼び出すことができるように、左辺値を右辺値に変換するだけです。


次のような移動コンストラクターがあるとします。

MyClass::MyClass(MyClass&& other): myMember(other.myMember)
{
    // Whatever else.
}

ステートメントother.myMemberを使用する場合、返される値は左辺値です。したがって、コードはcopyコンストラクターを使用してthis->myMemberを初期化します。しかし、これは移動コンストラクタであるため、otherは一時オブジェクトであり、したがってそのメンバーであることもわかっています。そのため、より効率的なmoveコンストラクターを使用してthis->myMemberを初期化します。 std::moveを使用すると、コンパイラがother.myMemberを右辺値参照のように扱い、必要に応じて移動コンストラクターを呼び出します。

MyClass::MyClass(MyClass&& other): myMember(std::move(other.myMember))
{
    // Whatever else.
}

保持する必要があるオブジェクトにはstd::moveを使用しないでください-移動コンストラクターは、渡されたオブジェクトを破壊することがほとんど保証されています。だからこそ、彼らは一時的にのみ使用されます。

お役に立てば幸いです!

26
Xavier Holt

あなたがタイプのオブジェクトT&&、右辺値を持っている場合は、このオブジェクトは他の誰もが、後でその内部状態に依存しないように、移動しても安全であることを意味します。

移動はコピーよりも高価ではないため、ほとんどの場合、移動する必要があります。それを移動するには、std::move関数を使用する必要があります。

安全だとしても、いつstd::moveを避けるべきですか?些細な例では使用しません、例えば:

 int x = 0;
 int y = std::move(x);

それ以外には、マイナス面はありません。コードが複雑にならない場合は、可能な限りIMHOに移動する必要があります。

移動したくない別の例は、戻り値です。この言語では、戻り値が(少なくとも)移動されることが保証されているため、

return std::move(x); // not recommended

(運が良ければ、 戻り値の最適化 ヒット、これは移動操作よりも優れています。)

3
Philipp Claßen

コピーを行わずに、オブジェクトのコンテンツを別の場所に「転送」する必要がある場合は、moveを使用できます。オブジェクトは、std :: moveを使用して、コピーを実行せずに一時オブジェクトのコンテンツを取得することもできます。

このリンクをチェックアウト

1
Rahul Tripathi