22

重複の可能性:
C++11 の右辺値とムーブ セマンティクスの混乱

私が正しいと思うのは、

std::string GetLine()
{
std::string str;
std::getline(std::cin, str);
return std::move(str);
}

しかし、このリンクでhttp://www.cprogramming.com/c++11/rvalue-references-and-move-semantics-in-c++11.html (ヘッダー部分を確認してください Returning an explicit rvalue-reference from a関数)

これは、ムーブ セマンティクスの 1 位の Google 検索ヒットであり、次のような同様の関数シグネチャを示しています。

int&& GetInt()
{
int x = 0;
// code here
return std::move(x);
}

私が他の場所で読んだことから && は右辺値参照を意味するため、この場合、存在しないオブジェクトへの参照を返します。

それで、それはどれですか?

(はい、int を移動しても実際のメリットがないことはわかっていますが、問題は、最初の関数で std::string または std::string&& の戻り値の型を使用するかどうかです。それがすべての型に対して行われるべき方法である場合。)

4

3 に答える 3

41

int&& GetInt()例が間違っていて、破棄されたオブジェクトへの参照を返していることは間違いありません。ただし、見逃していない限り、投稿したリンクには、ローカル変数への参照を返すコードは実際には表示されません。代わりに、グローバル変数への参照が返されますが、これは問題ありません。

戻るときに移動セマンティクスを使用する方法は次のとおりです。

std::string func()
{
    std::string rv;
    /* ... */
    return rv;
}

通常std::move()、オブジェクトを返すときは使用しないでください。これは、RVO が発生する可能性があるときは常に移動が暗黙的に許可されており、使用std::move()すると RVO が抑制されるためです。そのため、通常の状態に戻るよりも、使用std::move()が良くなることはなく、多くの場合悪化します。


繰り返しになりますが、使用std::move()すると、戻り値の最適化が抑制されるため、返される変数に単に名前を付けるよりも悪い場合があります。戻り値の最適化により、オブジェクトをコピーせずに呼び出し元にオブジェクトを返すことができます。

クラスの戻り値の型を持つ関数のreturnステートメントで、式が関数の戻り値の型と同じ cv-unqualified 型を持つ不揮発性自動オブジェクト (関数または catch-clause パラメーター以外) の名前である場合、自動オブジェクトを関数の戻り値に直接構築することにより、コピー/移動操作を省略できます

— [class.copy] 12.8/31

ただし、を使用std::move()すると、return 式が返すオブジェクトの名前になることはありません。代わりに、式はより複雑になり、言語で特別な処理を行うことはできなくなりました。

オブジェクトに名前を付けるだけで使用するよりも悪くない理由std::move()は、必要なく式をすでに右辺値として扱うことができるという別の規則があるためstd::move()です。

コピー操作の省略の基準が満たされているか、ソース オブジェクトが関数パラメーターであり、コピーされるオブジェクトが左辺値によって指定されているという事実を除いて満たされる場合、コピーのコンストラクターを選択するためのオーバーロードの解決は次のとおりです。オブジェクトが右辺値によって指定されたかのように最初に実行されます。

于 2012-08-17T18:51:32.943 に答える
11

質問に答えると、次のようになりstringます。何もせずmove、RVO を使用 (依存) します。

std::string func()
{
    std::string rv;
    /* ... */
    return rv;
}

これは、一般的に行われるべき方法です。(r 値かどうかに関係なく) 参照を一時的に返すことはできません。

于 2012-08-17T18:43:43.457 に答える
4

return std::move(str);がローカル変数であるかどうかを言う必要はありませんstr。変数が戻り値の最適化の基準を満たす場合、returnステートメント内で変数は右辺値参照にバインドされます。

また、左辺値参照でも右辺値参照でもなく、おそらくローカル変数への参照を返すべきではないことに注意してください。

つまり、次のものが必要です。

int foo() { int x; /*...*/ return x; }

std::string bar() { std::string str; /*...*/ return str; }
于 2012-08-17T18:53:27.683 に答える