没有初始化列表 vs. 带有空括号对的初始化列表

3
这是从此主题复制粘贴的:Initializing fields in constructor - initializer list vs constructor body 作者解释了以下等价性:
    public : Thing(int _foo, int _bar){
        member1 = _foo;
        member2 = _bar;
    }

is equivalent to

    public : Thing(int _foo, int _bar) : member1(), member2(){
        member1 = _foo;
        member2 = _bar;
    }

我的理解是:

  • 片段1是默认初始化的情况(因为缺少初始化列表)。
  • 片段2是值初始化的情况(空括号对)。

这两者有何等价之处?


4
仅针对非POD用户定义类型,这两者才是等价的。对于内置类型来说,默认初始化意味着没有初始化。 - juanchopanza
3
不是所有用户定义的类型,而是仅限非POD类型! - Nawaz
1
@Nawaz 好观点。已修复。 - juanchopanza
2
@DyP:POD类不能包含用户定义的构造函数,也不能包含任何聚合体。 因此,它及其包含的内容的默认构造函数必须是基本上是NOPs类型的(例如,像“int”的)。 - Jerry Coffin
1
@Nawaz,真正产生差异的不是POD特性,而是类是否具有用户定义的构造函数。例如,如果一个类有虚函数,它就不是POD,但在这两种情况下的行为仍然不同。 - James Kanze
显示剩余5条评论
2个回答

3

你的理解是正确的(假定member1member2的类型为'int')。两种形式不等价;在第一种情况下,成员变量根本没有初始化,直到赋值后才能使用。在第二种情况下,成员变量将被初始化为0。只有当成员变量是类类型且具有用户定义构造函数时,这两种形式才是等价的。


只有当成员是具有用户定义构造函数的类类型时,这两种表述才是等价的。如果隐式声明的默认构造函数被删除(使得两个版本都不合法)。 - dyp
@DyP或者如果它不可访问。每当两种形式中的任何一种不能编译时,代码显然是不等价的。 - James Kanze
每当两种形式中的任意一种无法编译时,咦?我的意思是,在两种情况下,值初始化 被定义为 默认初始化:1)如果存在用户提供的默认构造函数 2)如果默认构造函数被删除。 - dyp
@DyP:根据“好像规则”,对于非类类型,它们也可以是等效的。(请查看我的答案并指出我可能犯的任何错误。) - Cassio Neri
@CassioNeri 可能是这样。如果您在初始化之前意外使用它们,那么您将具有未定义的行为,因此编译器可以执行任何它想要的操作,包括将初始化上移至其应该出现的地方以使代码正常工作。 - James Kanze
显示剩余2条评论

1

你是正确的,但作者也有一定的正确性!

你的解释完全正确,其他人给出的答案也是如此。总之,如果 member1member2 是非 POD 类型,则这两个代码片段是等价的。

对于某些 POD 类型,在某种意义上它们也是等价的。现在,让我们简化一下,假设 member1member2 的类型为 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() // initialization line
    {
        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   ; extra line #1
   c:   c7 00 00 00 00 00       movl   $0x0,(%eax)       ; extra line #2
  12:   8b 45 fc                mov    -0x4(%ebp),%eax   ; extra line #3
  15:   c7 40 04 00 00 00 00    movl   $0x0,0x4(%eax)    ; extra line #4
  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多了四行额外的代码(如上所示)。这些额外的代码将两个成员初始化为零。

即使对于非 POD 类型,它们可能产生相同的代码。但是,只有当成员类型没有用户提供的默认构造函数或默认构造函数被删除时,它们在语义上才是等效的。(这也包括某些非 POD 类,参见 James Kanze 对 OP 的评论。) - dyp

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接