构造函数中的 const int ref 可以安全地绑定到文字吗?

Can a const int ref in a constructor safely bind to a literal?

我知道该标准有一个关于延长临时对象生命周期的例外,基本上说在构造函数中绑定 const 引用不会延长生命周期,但这是否也适用于文字?例如:

class C {
    private:
        const int& ref;
    public:
        C(const int& in)
            : ref{in}
        { }
};

如果我有一个函数返回这种类型的对象

C f() {
    C c(2);
    return c;
}

如果我知道 c.ref 的值绑定到文字,调用方是否会未定义它的值?

简短回答:评估 c.ref 几乎肯定是非法的(调用未定义的行为)。

长答案: 将引用绑定到整数文字时,您真正在做的是:

整数文字指的是所谓的“a value that is not associated with an object”。

要绑定对它的引用,需要创建一个包含相同值的对象。这样做的原因是引用(或指针)必须始终指向一个对象(而对象只不过是一点内存)。因此,创建了一个 临时 对象来保存该值。

只要创建它们的表达式正在被计算,临时对象就保证持续存在。由于您的对象存在的时间更长,保存您的值的临时对象将提前销毁,并且可能无法再访问该引用。

请注意,如果您在创建 c 的表达式中访问 c.ref,您实际上没问题。

。构造函数执行完毕后,您将无法使用该引用。
当非 class 类型的纯右值绑定到相同类型的 const-引用时,总是会引入临时值。因此,构造函数的参数引用将引用一个临时变量,一旦引用超出范围,该变量就会被销毁。发生这种情况后,成员引用就会悬空,并且尝试访问该引用后面的存储值会导致 UB。 [dcl.init.ref]/5:

A reference to type “cv1 T1” is initialized by an expression of type “cv2 T2” as follows:

  • If the reference is an lvalue reference and the initializer expression
    • is an lvalue (but is not a bit-field), and [..]
    • has a class type (i.e., T2 is a class type) [..]
  • Otherwise, the reference shall be an lvalue reference to a non-volatile const type (i.e., cv1 shall be const), or the reference shall be an rvalue reference.

    • If the initializer expression

      • is an xvalue (but not a bit-field), class prvalue, array prvalue or function lvalue and [..]
      • has a class type [..]
    • Otherwise: (5.2.2.1)

      • If T1 is a class type [..]
      • If T1 is a non-class type, a temporary of type “cv1 T1” is created and copy-initialized (8.5) from the initializer expression. The reference is then bound to the temporary.

毫不奇怪,整数文字确实是纯右值。 [expr.prim.general]/1:

A string literal is an lvalue; all other literals are prvalues.

最后,如果不清楚,[class.temporary]/5:

The temporary to which the reference is bound or the temporary that is the complete object of a subobject to which the reference is bound persists for the lifetime of the reference except:

  • A temporary bound to a reference member in a constructor’s ctor-initializer (12.6.2) persists until the constructor exits.