2

这是本主题的复制粘贴在构造函数中初始化字段 - 初始化列表与构造函数主体

作者解释了以下等价性:

    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

2 回答 2

3

您的理解是正确的(假设member1并且member2 类型为 `int)。这两种形式是等价的;首先,成员根本没有初始化,并且在分配之前不能使用。在第二种情况下,成员将被初始化为 0。仅当成员是具有用户定义的构造函数的类类型时,这两个公式才等效。

于 2013-10-16T15:29:00.347 回答
1

你是对的,但作者也是对的

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

对于某些 POD 类型,它们在某种意义上也是等价的。好吧,让我们再简化一点,假设member1member2type int。然后,根据as-if-rule ,允许编译器将第二个片段替换为第一个片段。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);

使用 GCC 4.8.1 选项-O1。(__atribute((noinline))__阻止编译器内联函数)。那么无论初始化行是否存在,生成的汇编代码都是相同的:

-O1有或没有初始化

   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。这些额外的行将两个成员初始化为零。

于 2013-10-16T15:47:56.640 回答