你是正确的,但作者也有一定的正确性!
你的解释完全正确,其他人给出的答案也是如此。总之,如果 member1
和 member2
是非 POD 类型,则这两个代码片段是等价的。
对于某些 POD 类型,在某种意义上它们也是等价的。现在,让我们简化一下,假设 member1
和 member2
的类型为 int
。然后,在 as-if 规则 下,编译器被允许将第二个代码片段替换为第一个代码片段。实际上,在第二个代码片段中,member1
首先被初始化为 0
这个事实是不可观察的。只有对 _foo
的赋值才是可观察的。这与编译器允许替换这两行代码的推理是相同的。
int x = 0;
x = 1;
用这个
int x = 1
例如,我已经编译了这段代码。
struct Thing {
int member1, member2;
__attribute__ ((noinline)) Thing(int _foo, int _bar)
: member1(), member2()
{
member1 = _foo;
member2 = _bar;
}
};
Thing dummy(255, 256);
使用选项
-O1
,GCC 4.8.1会生成相同的汇编代码,无论初始化行是否存在。(
__attribute((noinline))__
防止编译器内联函数)。
0: 8b 44 24 04 mov 0x4(%esp),%eax
4: 89 01 mov %eax,(%ecx)
6: 8b 44 24 08 mov 0x8(%esp),%eax
a: 89 41 04 mov %eax,0x4(%ecx)
d: c2 08 00 ret $0x8
另一方面,当使用
-O0
编译时,汇编代码会因初始化行的存在与否而有所不同:
-O0
无初始化
0: 55 push %ebp
1: 89 e5 mov %esp,%ebp
3: 83 ec 04 sub $0x4,%esp
6: 89 4d fc mov %ecx,-0x4(%ebp)
9: 8b 45 fc mov -0x4(%ebp),%eax
c: 8b 55 08 mov 0x8(%ebp),%edx
f: 89 10 mov %edx,(%eax)
11: 8b 45 fc mov -0x4(%ebp),%eax
14: 8b 55 0c mov 0xc(%ebp),%edx
17: 89 50 04 mov %edx,0x4(%eax)
1a: c9 leave
1b: c2 08 00 ret $0x8
1e: 90 nop
1f: 90 nop
-O0
带有初始化
0: 55 push %ebp
1: 89 e5 mov %esp,%ebp
3: 83 ec 04 sub $0x4,%esp
6: 89 4d fc mov %ecx,-0x4(%ebp)
9: 8b 45 fc mov -0x4(%ebp),%eax
c: c7 00 00 00 00 00 movl $0x0,(%eax)
12: 8b 45 fc mov -0x4(%ebp),%eax
15: c7 40 04 00 00 00 00 movl $0x0,0x4(%eax)
1c: 8b 45 fc mov -0x4(%ebp),%eax
1f: 8b 55 08 mov 0x8(%ebp),%edx
22: 89 10 mov %edx,(%eax)
24: 8b 45 fc mov -0x4(%ebp),%eax
27: 8b 55 0c mov 0xc(%ebp),%edx
2a: 89 50 04 mov %edx,0x4(%eax)
2d: c9 leave
2e: c2 08 00 ret $0x8
31: 90 nop
32: 90 nop
33: 90 nop
请注意,使用初始化的
-O0
比未使用初始化的
-O0
多了四行额外的代码(如上所示)。这些额外的代码将两个成员初始化为零。