在以下程序中:
int Func()
{
int a = { 10 };
return a;
}
int main()
{
int& r = (int&)(const int&)Func();
r = 5;
}
r
是对类型int
的临时引用。但是,除非临时将它们临时分配给引用,否则它们会立即被销毁。上面的分配似乎不正常。在标准C ++中使用r
是否安全?
答案 0 :(得分:1)
简介: 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
是要转换为的类型)描述:
如果
T
是引用类型,则效果与执行 一些发明的临时变量T t(e);
(11.6)的声明和初始化t
,然后将临时变量用作转换结果
在这种情况下,T
是const 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)中;它仅出现在C ++ 17后的草案中。
该决议的状态为DRWP,据我所知,这意味着它追溯适用于C ++ 17,但不适用于C ++ 14(如果有人想确认或更正这一点,那就太好了。)
无论如何,在某些情况下,此分辨率可以延长参考链的生命周期。文字是(N4762 class.temporary / 6):
[...]如果 glvalue设置为引用的生存期,则引用绑定到的临时对象或作为引用绑定到的子对象的完整对象的临时对象将在引用的生存期内持续存在。参考已绑定 通过以下之一:
- [...]
- 将
const_cast
,static_cast
,dynamic_cast
或reinterpret_cast
转换为glvalue操作数,而无需用户定义的转换,该glvalue操作数是这些表达式之一,而指操作数指定的对象,或其完整对象或其子对象,
在CWG1299之前,该段落仅适用于从prvalue初始化引用,但是现在,如果指定的对象是临时对象,则它可适用于从任何表达式类别初始化引用的情况。
请注意,临时物化在C ++ 17中的工作方式是,物化发生时prvalue会转换为xvalue,而该xvalue是上面粗体文本所指的glvalue。
现在甚至包括一个示例来确认这一点:
const int& b = static_cast<const int&>(0);
//临时int与b的生存期相同
另一个删除的答案中显示的编译器行为必须采用CWG1299的分辨率。