将类型为“int”的临时对象转换为引用安全吗?

Is casting a temporary with type `int` to a reference safe?

在以下程序中:

int Func()
{
    int a = { 10 };
    return a;
}
int main()
{  
    int& r = (int&)(const int&)Func();
    r = 5;        
}

r 是对 int 类型临时对象的引用。但是临时对象会立即被销毁,除非它们通常被分配给一个引用。上面的分配似乎不正常。在标准 C++ 中使用 r 安全吗?

简介: C 风格的转换等同于 (C++17 [expr.cast]):

int& r = const_cast<int&>( static_cast<const int&>(Func()) );

在子表达式 static_cast<const int&>(Func()) 中,行为由 C++17 [expr.static.cast]/4 描述(其中 T 是要转换为的类型):

If T is a reference type, the effect is the same as performing the declaration and initialization T t(e); for some invented temporary variable t (11.6) and then using the temporary variable as the result of the conversion

在本例中Tconst int&,所以引用的初始化类似于const int& t(Func());

这段代码现在有两个问题:

  • 临时文件的类型
  • 涉及的临时对象的生命周期

临时的类型是const int (C++17 [dcl.init.ref]/5.2.1.2)。因此,您的代码通过修改 const 对象导致未定义的行为。 Link to other SO question on this topic

对于此答案的其余部分(解决生命周期问题),我假设您将 r = 5 更改为仅显示 r.

的语句

引用链接的行为随着 CWG 1299 的应用而改变。该缺陷于 2011 年 4 月提交,并于 2017 年 3 月解决。该解决方案未出现在 C++17 (N4659) 中;它只出现在 post-C++17 草稿中。

该决议的状态为 DRWP,我的理解是这意味着它追溯适用于 C++17 但不适用于 C++14(如果有人想确认或更正这一点,那就太好了)。


无论如何,此解决方案在某些情况下可以延长引用链的生命周期。写法是(N4762 class.temporary/6):

[...] The temporary object to which the reference is bound or the temporary object that is the complete object of a subobject to which the reference is bound persists for the lifetime of the reference if the glvalue to which the reference is bound was obtained through one of the following:

  • [...]
  • a const_cast, static_cast, dynamic_cast, or reinterpret_cast converting, without a user-defined conversion, a glvalue operand that is one of these expressions to a glvalue that refers to the object designated by the operand, or to its complete object or a subobject thereof,

在 CWG1299 之前,本段仅适用于从纯右值初始化引用,但现在如果指定对象是临时对象,它可以适用于从任何表达式类别初始化引用的情况。

请注意,临时物化 在 C++17 中的工作方式是,当物化发生时,prvalue 被转换为一个 xvalue,这个 xvalue 是 glvalue 所引用的上面的粗体文字。

现在甚至包括一个例子来证实这一点:

const int& b = static_cast<const int&>(0); // temporary int has same lifetime as b

另一个已删除的答案中显示的编译器行为必须应用 CWG1299 的决议。