以下を考慮してください。
#include <string>
using std::string;
string middle_name () {
return "Jaan";
}
int main ()
{
string&& danger = middle_name(); // ?!
return 0;
}
これは何も計算しませんが、エラーなしでコンパイルされ、私が混乱していると思うことを示しています。danger
ぶら下がっている参照ですよね?
右辺値参照はダングリング参照を許可しますか?
「ダングリング右辺値参照を作成することは可能ですか」という意味であれば、答えはイエスです。ただし、あなたの例は、
string middle_name () {
return "Jaan";
}
int main()
{
string&& nodanger = middle_name(); // OK.
// The life-time of the temporary is extended
// to the life-time of the reference.
return 0;
}
完全に問題ありません。この例(Herb Sutter による記事) も安全にする同じ規則がここに適用されます。純粋なrvalueで参照を初期化すると、一時オブジェクトの有効期間が参照の有効期間まで延長されます。ただし、ダングリング参照を生成することはできます。たとえば、これはもはや安全ではありません。
int main()
{
string&& danger = std::move(middle_name()); // dangling reference !
return 0;
}
(純粋なrvalueではないstd::move
) を返すため、一時的な有効期間を延長するルールは適用されません。ここでは、いわゆるxvalueを返します。xvalueは名前のない右辺値参照です。そのため、関数の実装を見ずに、返された参照が何を参照しているかを推測することは基本的に不可能です。string&&
std::move
右辺値参照は右辺値にバインドします。右辺値は、prvalueまたはxvalue [説明] のいずれかです。前者にバインドしてもダングリング参照が作成されることはありませんが、後者にバインドすると可能性があります。T&&
そのため、関数の戻り値の型としてを選択することは、一般的に悪い考えです。std::move
は、この規則の例外です。
T& lvalue();
T prvalue();
T&& xvalue();
T&& does_not_compile = lvalue();
T&& well_behaved = prvalue();
T&& problematic = xvalue();
danger
ぶら下がっているリファレンスですよね?
const &
:を使用した場合と同じようdanger
に、右辺値の所有権を取得します。