【问题标题】:Const reference and lvalue [duplicate]常量引用和左值
【发布时间】:2014-05-15 17:26:00
【问题描述】:

我们不能写int& ref = 40,因为我们需要在右侧写lvalue。但是我们可以写const int& ref = 40。为什么这可能? 40 是 rvalue 而不是 lvalue

我知道这是个例外,但为什么呢?

【问题讨论】:

    标签: c++ lvalue rvalue


    【解决方案1】:

    正如 Stroustrup 所说:

    const T& 的初始值设定项不必是左值,甚至不必是类型 T. 在这种情况下:

    [1] 首先,必要时应用到 T 的隐式类型转换。

    [2] 然后,将结果值放在一个临时变量中 键入 T。

    [3] 最后,这个临时变量被用作 初始化器。

    所以,当你输入const int& ref = 40时,会在后台创建临时int变量,并将ref绑定到这个临时变量。

    【讨论】:

      【解决方案2】:

      语言中有一条规则允许将 const 左值引用绑定到右值。该规则的主要原因是,如果它不存在,那么您必须提供不同的函数重载才能使用临时变量作为参数:

      class T; // defined somewhere
      T f();
      void g(T const &x);
      

      有了这个规则,你可以做g(f()),没有它,你必须创建一个不同的g重载,它需要一个右值(这是从那时甚至没有语言中的右值引用!)

      【讨论】:

      • 我仍然不确定为什么lifetime is extended,虽然:-(
      • @KerrekSB:我想最初的原因是这样你可以写T const& _ = ...;T const _ = ...;,两者都可以工作,当表达式产生引用时前者效率更高(没有副本)。这确实很不幸,因为它让很多东西溜进来。
      • @KerrekSB:我想我已经在链接的问题中解决了这个问题。这是允许在一般上下文中绑定(不仅在函数参数中)并且不希望它在每次使用时导致未定义行为的副作用。如果没有生命周期延长:T const& x = f(); 后跟 any odr-use of x 将是未定义的行为,提出了为什么首先允许这样做的问题?因此,您要么提供一致性(any 上下文中的引用绑定)并延长生命周期,要么接受不一致并且不需要延长生命周期。语言是前者。
      • 为了简洁,我完全搞砸了。阅读上面的odr-use,不是odr-use,而是访问真实对象的任何使用(左值-右值转换,访问任何成员...)
      • 嗯,好吧,我仍然不相信(正如我在另一篇文章中所说的那样)——“完整表达式结束”规则似乎工作得很好,并且可以延长生命周期同样令人惊讶(典型示例是通过另一个返回引用的函数传递引用)。所以我仍然对贡献持开放态度:-)
      【解决方案3】:

      为什么会这样?

      40 在这里是一个文字。常量引用可以用文字和临时变量初始化以延长它们的生命周期。这可以通过编译器来完成:

      int const& ans = 40;
      // transformed:
      int __internal_unique_name = 40;
      int const& ans = __internal_unique_name;
      

      另一种情况是当你有一个函数时,例如:

      void f( std::string const& s);
      

      你想用它来调用它

      f( "something");
      

      这个临时变量只能绑定到 const 引用。

      【讨论】:

      • 非常量引用也是如此...
      • @DavidRodríguez-dribeas 不是提供的第二种情况
      • 这正是编译器将为您做的事情,它将调用映射到:std::string __tmp("something"); f(__tmp);。那是 因为你可以 不是允许 const 引用(单独)的理由,正如 Solaris CC 和 VS 都支持绑定非-const 通过执行完全相同的操作来引用临时对象。
      • @DavidRodríguez-dribeas 真实,已编辑
      【解决方案4】:

      您可以将右值绑定到 const 引用。该语言保证绑定对象一直存在,直到引用范围结束,甚至静态调用正确的析构函数。这是例如在 ScopeGuard 实现 (http://www.drdobbs.com/cpp/generic-change-the-way-you-write-excepti/184403758?pgno=2) 中使用以具有类似虚拟析构函数的行为,而无需为虚拟方法调用付费。

      【讨论】:

      • 编译器在这件事上没有选择。语言规则决定了生命周期。
      猜你喜欢
      • 2011-05-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-06
      • 1970-01-01
      • 2013-07-20
      • 1970-01-01
      • 2015-12-18
      相关资源
      最近更新 更多