【问题标题】:Why is value-initialization specified as not calling trivial default constructors?为什么将值初始化指定为不调用平凡的默认构造函数?
【发布时间】:2020-12-08 04:39:41
【问题描述】:

T 类型的对象进行值初始化意味着:

...

— 如果T 是一个(可能是 cv 限定的)类类型,没有用户提供或删除的默认构造函数,则该对象为零初始化并检查默认初始化的语义约束,如果 @987654323 @ 有一个重要的默认构造函数,对象是默认初始化的;

我理解这里的意图:如果用户没有为T 声明默认构造函数,或者在其第一个声明中明确默认了它,那么值初始化的零初始化传递将确保某些直接成员对象的值(例如基本类型的对象)不会留下不确定的值。

我不明白为什么第二遍被指定为“检查默认初始化的语义约束,如果T 有一个非平凡的默认构造函数,则该对象是默认初始化的”。对我来说,这与只是说“对象是默认初始化的”相同(无论默认构造函数是否微不足道)。如果构造函数实际上是微不足道的,调用它应该与不调用它相同。标准不需要告诉编译器不要生成调用,因为这种优化在 as-if 规则下是允许的,任何好的编译器都会这样做。

我错过了什么吗?在值初始化上下文中,调用一个普通的默认构造函数与不调用它有什么不同吗?

【问题讨论】:

  • 可能是为了避免您引用的“对象是零初始化的”和“否则,不执行初始化”之间的混淆。默认初始化的一部分。

标签: c++ language-lawyer


【解决方案1】:

我无法找到对我的问题的权威答案。但是,看看 C++03 标准,我有一个粗略的想法。 C++03定义T类型的值初始化如下:

  • 如果T是具有用户声明构造函数的类类型,则调用默认构造函数;
  • 如果T 是没有用户声明的构造函数的非联合类类型[这意味着编译器隐式声明了默认构造函数],则每个基类子对象和成员子对象都是值初始化的;
  • [...]

第二个要点确保标量类型的直接子对象是零初始化的,因此比简单地调用隐式默认构造函数“更强”。这就是值初始化背后的意图。

所以 C++03 中的措辞是有道理的,自然会导致以下结果:当默认构造函数是微不足道的时,实际上不会发生任何函数调用。

在 C++11 中,零初始化的定义已更改,因此它还将填充位初始化为零 (CWG 694)。我的猜测是,围绕值初始化的措辞已更改,以保证在默认构造函数的情况下,值初始化也可以保证将填充位归零。所以在 C++11 中,当 T(没有用户提供的默认构造函数的类型)被值初始化时,所发生的事情比仅仅对 T 的所有直接子对象进行值初始化要强。相反,整个T 对象首先初始化为零(以确保填充为零),然后调用默认构造函数。

但同样,我们的问题是为什么在默认构造函数是微不足道的情况下会出现异常。进行措辞更改的paper 没有解释为什么要放入该异常,但我们现在可以看到它保留了 C++03 的行为,其中根本没有调用微不足道的默认构造函数。我的猜测是作者故意输入措辞以保留这种行为。正如我在问题中所说,调用一个简单的默认构造函数不会损害性能,因为编译器会优化调用。但也许作者担心如果 C++11 指定了一个调用(对一个微不足道的默认构造函数)而 C++03 没有,那么某些东西(他们可能无法预料到)会中断。保持没有这样的调用比担心这个更容易。

不过,我们应该注意到 C++11 的行为与 C++03 的行为以及填充的零初始化并不完全相同。假设我们有一个这样的类型:

struct T {
    struct U { U() {} } u;
    int x;
};

在 C++03 中,T 的值初始化意味着调用 U::U,然后将 x 初始化为零。在 C++11 中,这意味着将整个 T 对象初始化为零,然后调用 T::T,进而调用 U::U。因此,与 C++03 相比,C++11 在这里多了一个函数调用。因此,尽管作者尽了最大努力,但行为并不相同。但据我所知,这种差异不会破坏任何代码。

在 C++11 到 C++17 中,调用普通默认构造函数和不调用它之间存在区别。如果调用它,可能会导致封闭表达式无法成为常量表达式(请参阅here)。这是我所知道的唯一区别。也许 N2762 的作者打算编译这样的代码,这就是他们说不调用普通构造函数的原因。但是,我认为这不太可能,因为它是一种“边缘情况”。

【讨论】:

    猜你喜欢
    • 2020-03-24
    • 2018-11-24
    • 2015-01-12
    • 1970-01-01
    • 2017-12-09
    • 2021-12-16
    • 2020-08-05
    • 2014-07-25
    • 1970-01-01
    相关资源
    最近更新 更多