【问题标题】:No initializer list vs. initializer list with empty pairs of parentheses没有初始化列表与带有空括号对的初始化列表
【发布时间】:2013-10-16 15:15:59
【问题描述】:

这是本主题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;
    }

我的理解是

  • sn-p 1 是默认初始化的情况(因为没有初始化列表)
  • sn-p 2 是值初始化(空括号对)的情况。

这两个如何等效?

【问题讨论】:

  • 这两者仅对非 POD 用户定义类型等价。对于内置,默认初始化意味着没有初始化。
  • @juanchopanza:不是所有用户定义的类型,只有非 pod 类型!
  • @Nawaz 好点。固定。
  • @DyP:POD 类不能包含用户定义的 ctor,它也不能聚合任何东西。因此,它的默认 ctor 及其包含的任何内容都必须是基本上是 NOP 的那种(例如,像int's)。
  • @Nawaz 这不是 POD 的区别;而是该类是否具有用户定义的构造函数。 (如果一个类有虚函数,比如它不是一个POD,但是这两种情况下的行为还是不一样的。)

标签: c++ initializer-list


【解决方案1】:

您的理解是正确的(假设member1member2 有类型`int)。这两种形式等价;在里面 首先,成员根本没有初始化,不能 在分配之前一直使用。在第二种情况下, 成员将被初始化为 0。这两个公式只是 如果成员是用户定义的类类型,则等效 构造函数。

【讨论】:

  • "只有当成员是具有用户定义构造函数的类类型时,这两个公式才等效。"如果隐式声明的默认 ctor 被删除(使两个版本都格式错误)。
  • @DyP 或者如果它无法访问。任何时候这两种形式之一不能编译,代码显然是不等价的。
  • “任何时候两种形式之一都无法编译” 嗯?我的意思是 value-initialization 在两种情况下被定义为 default-initialization :1)如果有用户提供的默认ctor 2)如果默认ctor被删除.
  • @DyP:在 as-if-rule 下,它们也可以等效于非类类型。 (请查看我的回答并指出我可能犯的任何错误。)
  • @CassioNeri 可能是。如果你在初始化之前不小心使用了它们,你就会有未定义的行为,所以编译器可以做任何它想做的事情,包括通过将初始化移动到它所属的位置来使代码工作。
【解决方案2】:

你是对的,但作者也有点对!

您的解释和其他人给出的答案一样完全正确。总之,如果member1member2 是非POD 类型,那么这两个sn-ps 是等价的。

对于某些 POD 类型,它们在某种意义上也是等价的。好吧,让我们再简化一点,假设member1member2 的类型为int。然后,根据as-if-rule,编译器允许用第一个sn-p替换第二个sn-p。实际上,在第二个 sn-p 中,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 多出四行(上面标记)。这些额外的行将两个成员初始化为零。

【讨论】:

  • 即使对于非 POD 类类型,它们也可能产生相同的代码。但是,仅当成员类型没有用户提供的默认 ctor 或默认 ctor 被删除时,它们在语义上是等效的。 (这也包括某些非 POD 类,请参阅 James Kanze 的 comment to the OP。)
猜你喜欢
  • 2018-12-12
  • 2011-08-09
  • 2021-03-25
  • 2021-07-09
  • 2020-05-14
  • 1970-01-01
  • 2016-12-11
  • 1970-01-01
  • 2012-11-21
相关资源
最近更新 更多