在以下程序中:
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
是被强制转换的类型):
如果
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的分辨率。