考虑以下。
#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;
}
因为std::move
返回 a string&&
(它不是纯rvalue )延长临时生命周期的规则不适用。在这里,std::move
返回一个所谓的xvalue。xvalue只是一个未命名的右值引用。因此,它可以引用任何东西,如果不查看函数的实现,基本上不可能猜测返回的引用指的是什么。
右值引用绑定到右值。rvalue 是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
获得右值的所有权一样。