[英]Aggregate initialization of a struct, using its own data members
这是关于这个的第n个问题,但我找不到完全相同的...
假设以下代码:
#include <iostream>
struct S {
int x;
int y;
};
class C {
public:
S s;
C() : s{123, s.x} {}
};
int main() {
std::cout << C().s.y << '\n';
}
可以像这样初始化sy
吗? (只有JetBrains的ReSharper通过以下方式抱怨它: Object member this->sx might not be initialized
)。
如果有人用标准引用确认答案,那就太好了。
来自C ++ 14
8.5.1聚合[dcl.init.aggr]
1聚合是一个数组或类(第9条),没有用户提供的构造函数(12.1),没有私有或受保护的非静态数据成员(第11条),没有基类(第10条),也没有虚函数( 10.3)。
2当初始化程序列表初始化聚合时,如8.5.4中所述,初始化程序列表的元素将作为聚合成员的初始化程序,增加下标或成员顺序。
这意味着首先用123初始化sx,然后用sx初始化sy
没有优化,GCC 6.3就会生成
C::C():
push rbp
mov rbp, rsp
mov QWORD PTR [rbp-8], rdi
mov rax, QWORD PTR [rbp-8] # read address of s
mov DWORD PTR [rax], 123 # write 123 to s.x (offset 0 from s)
mov rax, QWORD PTR [rbp-8] # read address of s again
mov edx, DWORD PTR [rax] # read contents of s.x to edx
mov rax, QWORD PTR [rbp-8] # read address of s
mov DWORD PTR [rax+4], edx # write s.y (offset 4 from s)
nop
pop rbp
ret
这符合标准所说的内容。
虽然似乎没有规则明确指出这个技巧是不正确的,但它还不足以具有明确定义的行为。
我认为评估顺序存在一些问题:
此规则定义了支撑列表中表达式的评估顺序; 当然,也有成员初始化的订单。
可以肯定地说,在对括号列表中的相应表达式进行求值之后,每个结构成员都被初始化(显然在初始化sy
之前评估了支撑列表中的sx
)。
但是,在评估支撑列表的第二个元素之前,似乎没有规则表明你的情况下的sx
必须被初始化,例如,程序可以在开始初始化struct字段之前评估括号列表中的所有表达式。
当然,缺乏规则并不容易证明,但如果不存在,则看起来像UB。
UPD : 来自@PaulFloyd的答案的规则确实非常类似于我的答案中遗漏的内容,也许它毕竟不是UB。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.