【问题标题】:Why `default` ctor zero-initializes class members?为什么`default` ctor对类成员进行零初始化?
【发布时间】:2021-12-16 07:09:23
【问题描述】:

给定两个具有不同构造函数的类:

#include <iostream>

struct A {
    int x;

    A() {};
};

struct B {
    int x;

    B() = default;
};

int main() {
    int x = 5;
    x = 7;

    printf("before: %d\n", x);

    new(&x) A();
    printf("%d\n", x);

    new(&x) B();
    printf("%d\n", x);
}

输出是:

before: 7
7
0

为什么default ctor 零初始化int x

【问题讨论】:

  • 这是一个有趣的结果,但由于未定义行为的性质,这并不表明B 实际上初始化了它的x 成员。例如,当我尝试它时,我得到了与您相同的结果,但是使用-O3 我得到的输出看起来像A 也将x 初始化为零,但显然不需要:godbolt.org/z/cxrn1WcT9
  • 我认为不是构造函数这样做,而是整数初始化,它是未定义的并且依赖于编译器
  • @vladon 从 C++11(我认为)开始,如果您为具有“默认默认 ctor”的类调用 new()(您的 B 类有一个)"the object is zero-initialized" 作为一种可能性值初始化。该页面上的案例2。然后它将被默认初始化,这是 A 和 B 的 NOP。
  • @Peter-ReinstateMonica 是的,但不是在星期六
  • @vladon 众所周知,StackOverflow 不工作——它避免工作,所以最好在安息日完成。

标签: c++ default-constructor value-initialization


【解决方案1】:

您使用的 value initialization (new A();) 与 default initialization (new A;) 不同。注意括号。

对于值初始化:

如果 T 是没有默认构造函数的类类型,或者具有用户提供或删除的默认构造函数,则该对象是默认初始化的;

还有:

如果 T 是具有既不是用户提供也不是删除的默认构造函数的类类型(也就是说,它可能是具有隐式定义或默认构造函数的类),则对象被零初始化,然后它如果它具有非平凡的默认构造函数,则默认初始化;

而且,关于"user-provided" 的定义:

如果函数是用户声明的并且在其第一次声明时没有显式默认或删除,则该函数是用户提供的。

A 有一个用户提供的构造函数,所以它属于第一种情况。只是调用它的构造函数,它什么都不初始化。

B 的构造函数是显式默认的,所以它不是用户提供的,也没有被删除,所以它属于第二种情况。它是zero-initialized,然后默认初始化。

【讨论】:

  • 我必须承认这些晦涩难懂的规则令人困惑。引入“默认默认构造函数”的可能性本质上是为了使程序员免于编写编译器已经非常清楚如何生成的代码(并且它也会自动维护!)。现在虽然我明确地说“做你一直做的事情”,但它做了一些不同的事情?难倒我了。也就是说,自 1989 年以来,零初始化应该是默认设置,而不是“什么都不做,让 UB 吃掉你”,并有可能在性能要求的 0.1% 中选择退出。
  • @Peter-ReinstateMonica 这里的诀窍是B() = defaultB 保留为微不足道的类型,而A() {} 则没有。如果你比较 A a{}; B b{}; 你会得到同样的情况。基本上= default 并不意味着“写一个空的构造函数”。这意味着“不要让任何东西妨碍生成编译器提供的默认构造函数”,这略有不同。从某种意义上说,它“做你一直做的事情”,因为B 相当于如果B() = default; 根本没有被编写。编辑:我同意未初始化成员的零初始化应该是默认设置,并且可以选择退出。
  • @Peter-ReinstateMonica 关于更喜欢零初始化,使用= default 更好,因为它结合new T() 来做到这一点。因此,如果您更喜欢零初始化,我会认为 = default 是一种改进,即使它与您自己编写空构造函数会发生的情况不一致。
  • 感谢您的澄清!我没有意识到这一点:隐式定义的默认 ctor 会做同样的事情吗?这更有意义。我很困惑,因为“如果 T 是没有默认构造函数的类类型 [...] 对象是默认初始化的”。我认为这意味着隐含的情况,因为如果真的有 no 默认 ctor 我不能调用 T()!?
  • 我问过here
猜你喜欢
  • 2013-10-14
  • 2019-05-30
  • 1970-01-01
  • 2020-02-25
  • 1970-01-01
  • 1970-01-01
  • 2015-03-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多