请考虑以下内容。
#include <string>
using std::string;
string middle_name () {
return "Jaan";
}
int main ()
{
string&& danger = middle_name(); // ?!
return 0;
}
这不计算任何东西,但它编译时没有错误,并且演示了一些让我感到困惑的事情:danger
是一个悬空引用,不是吗?
答案 0 :(得分:41)
右值引用是否允许悬空引用?
如果你的意思是“是否可以创建悬空右值参考”,那么答案是肯定的。但是,你的例子
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;
}
非常好。同样的规则适用于this example(Herb Sutter的文章)也是安全的。如果使用 pure rvalue 初始化引用,则临时对象的生命周期将延长到引用的生命周期。不过,你仍然可以制作悬空参考。例如,这不再安全:
int main()
{
string&& danger = std::move(middle_name()); // dangling reference !
return 0;
}
因为std::move
返回string&&
(不 纯 rvalue )延长临时生命期的规则不适用。在这里,std::move
返回所谓的 xvalue 。 xvalue 只是一个未命名的右值引用。因此它可以引用任何东西,并且基本上不可能在不查看函数实现的情况下猜测返回的引用所引用的内容。
答案 1 :(得分:15)
rvalue引用绑定到rvalues。右值是 prvalue 或 xvalue [explanation]。绑定到前者永远不会创建悬挂引用,绑定到后者可能。这就是为什么选择T&&
作为函数的返回类型通常是个坏主意。 std::move
是此规则的例外。
T& lvalue();
T prvalue();
T&& xvalue();
T&& does_not_compile = lvalue();
T&& well_behaved = prvalue();
T&& problematic = xvalue();
答案 2 :(得分:3)
danger
是一个悬空参考,不是吗?
只不过是您使用了const &
:danger
获得了右值的所有权。