【问题标题】:Initializing a reference初始化引用
【发布时间】:2014-01-10 13:25:31
【问题描述】:

虽然我认为我理解 C++ 中的 rvaluelvalue 语义,但我似乎一遍又一遍地踩着奇怪的例子证明我不知道深蹲。

但是有两个非常简单和基本的,我不明白它们是如何工作的。在我编译它们之前,我认为没有一个可以,在我看到(1) 有效之后,我认为(2) 也可以。但是,(1) 有效,(2) 无效:

(1) const std::string &s = "asd";

这里发生了什么?我的猜测是一个临时的const string 对象是从"asd" 构造的,然后s 绑定到那个临时对象。但是在这一行之后临时对象不会被销毁,所以我们会留下一个无效的引用吗?

当我删除 const 限定符时:

(2) std::string &s = "asd";

我收到编译器错误(VS 2013):cannot convert from 'const char [4]' to 'std::string &'。这似乎反驳了我的理论,因为根据它(我的猜测),一个临时的string 对象将从"asd" 构造,然后分配给它s,这不会产生任何编译错误。

总结一下:

  • s 绑定到什么?
  • s 绑定的对象的生命周期是多少?
  • 是什么让(1) 编译而(2) 不编译(是std::string 中定义的一些转换运算符还是C++ 语义)?

【问题讨论】:

  • 这是一个const 参考。这是一个巨大的差异,因为您将 (1) 设为右值。函数f1(const string &s)f2(string &s) 也是如此,在第一种情况下您可以调用f2("my text const"),但另一种情况会失败。

标签: c++ reference


【解决方案1】:

(2) 不起作用,因为"asd"char const[]。编译器会将其(实际上)隐式转换为临时的string 右值。您不能将非常量引用分配给将立即超出范围的值。所以你的分析是正确的。

对于(1),我必须自己进行一些查找,但我想我在这里找到了答案:Does a const reference prolong the life of a temporary?

似乎该标准允许在将临时对象绑定到 const 引用时发生副本。 Unexpexted,我同意 :) 所以会再次隐式转换为临时的string 右值,并且因为引用现在是const,所以这个右值将被复制,所以它仍然存在。

【讨论】:

    【解决方案2】:

    TL;DR

    • 绑定到什么?
    • s 绑定的对象的生命周期是多少?

    对于一个新创建的临时std::string,它的寿命与s 一样长。

    是什么让 (1) 编译而 (2) 不编译?

    您不能对非左值进行非常量引用。

    相关引述

    引自 8.5.3 [dcl.init.ref]:

    对类型“cv1 T1”的引用由类型表达式初始化 “cv2 T2”如下:

    • [ .. 剪辑,不相关 .. ]​​i>
    • 否则[如果右手边不是左值],引用应该是对非易失性常量类型的左值引用(即cv1 应该是const),或者引用应该是一个右值引用。
      • [ .. 剪辑,不相关 .. ]
      • 否则,将创建一个“cv1 T1”类型的临时变量,并使用初始化表达式从初始化表达式中初始化 非参考复制初始化的规则(8.5)。参考资料 然后绑定到临时。如果 T1 与 T2 引用相关,则 cv1 应与 cv-qualification 相同或更高 cv-qualification 比,cv2。如果 T1 与 T2 参考相关,并且参考是 右值引用,初始化表达式不能是左值。

    在所有情况下,除了最后一个(即,创建和初始化一个 来自初始化表达式的临时),该引用被称为 直接绑定到初始化表达式。

    在您的情况下,您需要将const char* 转换为std::string,这会引入std::string 类型的临时变量。因为这不是一个左值,所以引用应该是const。这总结了为什么(2)不起作用。

    终生看一看 12.2 [class.temporary]:

    在两种情况下,临时对象在与完整表达式结尾不同的点被销毁。 [...]

    第二个上下文是引用绑定到临时的。引用绑定到的临时对象或作为引用绑定到的子对象的完整对象的临时对象在引用的生命周期内持续存在 [...]

    这意味着临时将只要您的const 引用。这就总结了为什么 (1) 确实有效。

    请注意,标准中有更多细节,其中包括一些极端情况,因此您可能需要完整阅读这些部分。

    【讨论】:

      【解决方案3】:

      s 绑定到什么?

      如您所推测的,到一个由字符串文字构造的临时std::string

      s 绑定的对象的生命周期是多少?

      临时的生命周期被延长以匹配引用的生命周期。通常,临时对象在创建它们的完整表达式结束时被销毁;这是该规则的一个例外。

      是什么让 (1) 编译而 (2) 不编译?

      另一个语言规则:临时文件不能绑定到非const 引用。这条规则有点古怪,但很有用:如果您不小心修改了临时对象而不是更持久的对象,它可以防止出现细微的错误。

      【讨论】:

        猜你喜欢
        • 2014-08-23
        • 1970-01-01
        • 2021-05-04
        • 2015-04-27
        • 2021-11-11
        • 2013-03-15
        • 2012-05-17
        • 2017-05-01
        • 2015-04-21
        相关资源
        最近更新 更多