右值引用是否允许悬空引用?

And*_*ack 31 c++ rvalue c++11

考虑以下.

#include <string>
using std::string;

string middle_name () {
    return "Jaan";
}

int main ()
{
    string&& danger = middle_name();   // ?!
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

这不会计算任何东西,但它编译时没有错误,并演示了一些让我感到困惑的事情:danger是一个悬空引用,不是吗?

sel*_*tze 42

右值引用是否允许悬空引用?

如果你的意思是"是否有可能创建悬空右值参考",那么答案是肯定的.然而,你的例子,

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;
}
Run Code Online (Sandbox Code Playgroud)

很好.同样的规则适用于此示例(Herb Sutter的文章)也是安全的.如果使用 rvalue初始化引用,则临时对象的生命周期将延长到引用的生命周期.不过,你仍然可以制作悬空参考.例如,这不再安全:

int main()
{
    string&& danger = std::move(middle_name());  // dangling reference !
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

由于std::move回报string&&(这是不是一个纯粹的右值),它扩展了临时的生活时不适用该规则.在这里,std::move返回一个所谓的xvalue.一个x值只是一个不知名的右值引用.因此它可以引用任何东西,并且基本上不可能在不查看函数的实现的情况下猜测返回的引用所引用的内容.

  • @Andres:我试着在答案中解释这一点.只有当初始化程序是纯rvalue时,编译器才能确切地知道要初始化的引用将引用什么.在这种情况下,正确的临时生命期可以并且将很容易扩展.如果初始化程序本身是一个引用,你通常不会真正知道*它究竟指的是什么对象.`std :: move`对编译器没有任何意义.std :: move的结果引用同一对象的信息不会保留在函数的类型中. (6认同)
  • 善意的'移动'的好例子出了差错! (4认同)
  • @sellibitze这是有道理的!引用对象的生命周期可以具有任何类型的生命周期,其中纯rvalue的生命周期很容易预测,因此可以轻松扩展. (3认同)
  • 对于为什么这需要_pure_ rvalues有直觉吗?xvalue案例看起来非常合理...... (2认同)
  • 请参阅http://stackoverflow.com/questions/42441791/lifetime-extension-prvalues-and-xvalues/42441832#42441832 值类别并不能确定对象的生命周期是否会延长。右边的值是否是xvalue并不足以决定rvalue的生命周期是否会延长。您能否更新答案以包括延长对象生命周期的实际位置,这样人们就不会被误导? (2认同)

fre*_*low 15

右值引用绑定到右值.右值是prvaluexvalue [ 说明 ].绑定到前者永远不会创建悬挂引用,绑定到后者可能.这就是为什么选择T&&函数的返回类型通常是个坏主意.std::move是这个规则的一个例外.

T&  lvalue();
T   prvalue();
T&& xvalue();

T&& does_not_compile = lvalue();
T&& well_behaved = prvalue();
T&& problematic = xvalue();
Run Code Online (Sandbox Code Playgroud)