请看下面的代码:
struct Temp{ int i = 0; };
Temp GetTemp() { return Temp{}; }
int main()
{
for (struct{Temp const & t; int counter;} v = {GetTemp(), 0};
v.counter < 10;
++v.counter)
{
// Is v.t guaranteed to not be a dangling reference?
std::cout << v.t.i << std::endl;
}
}
所以GetTemp()
返回一个临时对象,然后赋值给一个常量引用变量,但是这个常量引用变量是一个匿名局部结构体的成员。C++标准是否保证临时变量的生存期延长到循环终止之后?
考虑到this question,我本以为答案是否定的,也就是说,我在循环体中得到了一个悬空引用,然而,gcc和clang似乎延长了生存期(参见example on godbolt),甚至没有抱怨-fsanitize=undefined
,这让我感到惊讶。
2条答案
按热度按时间pkmbmrz71#
对于示例中的大括号聚合初始化,已保证since C++98的生存期延长(与类的链接/可见性属性无关)。这很直观,因为引用直接绑定到临时变量,而不是像你链接的问题那样通过一些中间的ctor参数。参见C14 FD中的[class.temporary],它概述了生存期扩展上下文。
另请参见这里的注解,它区分了C20以来的花括号初始化和括号初始化:
[Note 7:与 direct-list-initialization 相比,收缩转换([dcl.init.list])是允许的,指示符是不允许的,绑定到引用的临时对象的生存期不会延长([class.temporary]),并且没有大括号省略。
[* 示例 * 3:
niknxzdl2#
匿名结构中的常量引用成员变量是否会延长临时变量的生存期?
是的,
const
引用链是完整的。只有v
和v
在for
循环结束之前是活动的,因此被引用的Temp
的生存期被延长到那时。struct
是匿名的这一事实没有影响。class.temporary/4
有两种情况下临时变量会在完整表达式结束时被销毁。第一种情况是调用默认构造函数来初始化数组元素。如果构造函数有一个或多个默认参数,那么默认参数中创建的每个临时变量的销毁都将在构造下一个数组元素之前进行。
class.temporary/5
第二个上下文是当引用被绑定到一个临时对象时。引用所绑定到的临时对象或作为引用所绑定到的子对象的完整对象的临时对象在引用的生存期内持续存在除了:
生命期延长的例外情况均不适用于您的案例。