【问题标题】:Do rvalue references allow dangling references?右值引用是否允许悬空引用?
【发布时间】:2011-04-12 14:10:21
【问题描述】:

考虑以下内容。

#include <string>
using std::string;

string middle_name () {
    return "Jaan";
}

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

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

【问题讨论】:

  • 让我困惑的是,你可以在左侧使用 &&,什么时候有用?
  • @Viktor:右值引用可以绑定到一个临时的并且仍然可以修改。例如int &amp;&amp;variable_or_dummy = modify_var? move(var) : int();
  • 你命名一个右值它变成一个左值,所以在 main danger 是一个左值。右值或左值是表达式的属性

标签: c++ c++11 rvalue


【解决方案1】:

右值引用允许悬空引用吗?

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

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 右值初始化引用,则临时对象的生命周期会延长到引用的生命周期。不过,您仍然可以生成悬空引用。例如,这不再安全了:

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

因为std::move 返回一个string&amp;&amp;(它不是一个右值)延长临时生命周期的规则不适用。在这里,std::move 返回一个所谓的 xvaluexvalue 只是一个未命名的右值引用。因此,它可以引用任何东西,如果不查看函数的实现,基本上不可能猜出返回的引用所指的内容。

【讨论】:

  • 善意move-ing 出了差错!
  • @kts:不。它甚至无法编译,因为您无法使用右值表达式初始化非常量左值引用。如果你写string const&amp; danger = move(middle_name()); 它也不会工作。它会编译,但 danger 将是一个悬空引用。
  • 是否有直觉说明为什么这需要 pure 右值? xvalue 案例似乎完全合理......
  • @Andres:我试图在答案中解释这一点。只有当初始化器是纯右值时,编译器才确切知道要初始化的引用将引用什么。在这种情况下,正确临时的寿命可以并且将很容易地延长。如果初始化程序本身是一个引用,那么您通常并不真正知道它到底指的是什么对象。 std::move 对编译器没有任何意义。 std::move 的结果引用同一个对象的信息不保存在函数的类型中。
  • @sellibitze 这很有道理!被引用对象的生命周期可以有任何类型的生命周期,其中纯右值的生命周期很容易预测,因此可以轻松扩展。
【解决方案2】:

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

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

T&& does_not_compile = lvalue();
T&& well_behaved = prvalue();
T&& problematic = xvalue();

【讨论】:

  • +1 你是对的,不编写返回右值引用的函数是一个很好的经验法则。 std::move 和 std::forward 是明显的例外。
【解决方案3】:

danger 是一个悬空引用,不是吗?

如果您使用了const &amp;,则不会超过:danger 拥有右值的所有权。

【讨论】:

    猜你喜欢
    • 2021-11-09
    • 2021-06-14
    • 2011-07-04
    • 2017-04-11
    • 2011-04-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多