繁体   English   中英

使用自己的数据成员聚合结构的初始化

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM