【问题标题】:Aggregate initialization of a struct, using its own data members结构的聚合初始化,使用它自己的数据成员
【发布时间】:2017-08-31 05:46:34
【问题描述】:

这是关于这个的第 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';
}

这样初始化s.y可以吗? (只有 JetBrains 的 ReSharper 通过以下方式抱怨它:Object member this-&gt;s.x might not be initialized)。

如果有人用标准的引用来确认他们的答案,那就太好了。

【问题讨论】:

标签: c++ aggregate-initialization


【解决方案1】:

来自 C++14

8.5.1 聚合 [dcl.init.aggr]

1 聚合是一个数组或一个类(第 9 条),没有用户提供的构造函数 (12.1),没有私有或 受保护的非静态数据成员(第 11 条),无基类(第 10 条),无虚函数(10.3)。

2 当聚合被初始化列表初始化时,如 8.5.4 中所指定,初始化列表的元素 以递增的下标或成员顺序作为聚合成员的初始值设定项。

这意味着s.x首先用123初始化,然后s.y用s.x初始化。

没有优化,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

这与标准所说的一致。

【讨论】:

  • 那么优化呢?
  • 通过优化,包括 s.y 在内的大部分代码都被删除了,结果几乎是 "std::cout
  • 它们被采取作为初始化器并不一定意味着初始化也以相同的顺序执行。标准的这一部分说的是编译器必须尊重 xy 在结构定义中出现的顺序(“增加成员顺序”)。编译器对代码的实际处理并不是任何语言律师问题的合适证明。如果该标准实际上规定了特定的初始化顺序,那么它必须在其他地方这么说。
  • 我不太明白这条规则。 “采用”是否意味着元素都被评估并用作初始值设定项?好像是这样
  • 我的理解是成员字段是从初始化列表元素表达式复制初始化的。
【解决方案2】:

虽然似乎没有明确规定此技巧格式错误的规则,但仅具有明确定义的行为是不够的。

我认为它的评估顺序有一些问题:

this rule 定义了括号列表中表达式的计算顺序;当然,成员初始化也是有顺序的。

可以肯定地说,每个结构成员在计算括号列表中的相应表达式之后被初始化(显然,括号列表中的s.x 在初始化s.y 之前被计算)。

但是,似乎没有规则表明您的情况下 s.x 必须在评估大括号列表的第二个元素之前进行初始化,例如该程序甚至可以在开始初始化结构字段之前评估括号列表中的所有表达式。

当然,不存在规则并不容易证明,但如果不存在,则看起来像 UB。

UPDthe rule from @PaulFloyd's answer 确实与我的答案中缺少的内容非常相似,也许它毕竟不是 UB。

【讨论】:

    猜你喜欢
    • 2016-06-23
    • 2020-05-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-20
    • 2020-10-22
    • 1970-01-01
    相关资源
    最近更新 更多