34

考虑以下。

#include <string>
using std::string;

string middle_name () {
    return "Jaan";
}

int main ()
{
    string&& danger = middle_name();   // ?!
    return 0;
}

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

4

3 回答 3

45

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

如果您的意思是“是否可以创建悬空右值引用”,那么答案是肯定的。但是,您的示例

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返回一个所谓的xvaluexvalue只是一个未命名的右值引用。因此,它可以引用任何东西,如果不查看函数的实现,基本上不可能猜测返回的引用指的是什么。

于 2010-09-15T09:32:52.343 回答
17

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

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

T&& does_not_compile = lvalue();
T&& well_behaved = prvalue();
T&& problematic = xvalue();
于 2010-09-15T10:23:01.397 回答
3

danger是一个悬空的参考,不是吗?

就像您使用const &:danger获得右值的所有权一样。

于 2010-09-15T09:29:00.187 回答