构造函数中的 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.
我知道该标准有一个关于延长临时对象生命周期的例外,基本上说在构造函数中绑定 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 “cv2T2
” 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 “cv1T1
” 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.