调用普通的默认构造函数会显式地导致额外的赋值调用

时间:2018-05-21 10:40:33

标签: c++ constructor

Demo

首先是问题:我有一个带有默认构造函数的现有结构,它将它置于有效状态。我想要一个根本不进行初始化的NoInit构造函数。现有代码对成员变量有一些初始化 - 声明期间语句,因此struct B的示例我试图覆盖初始化 - 在声明期间语句通过显式调用std::atomic的默认构造函数。

std::atomic默认构造函数没有初始化:

  

默认构造函数很简单:不进行初始化   除了静态和线程局部对象的零初始化。

那么,为什么要调用默认构造函数导致程序集中的任何赋值?

struct A {
    std::atomic<long> a;
    std::atomic<long> b;
    int c;

    A() : a{1}, b{2}, c{3} {} // This is obviously fine.
    A(DefaultInit) : a(), b(), c() {} // Should this not be similar to NoInit?
    A(NoInit) {} // This is fine. Results in no code

};

第二个构造函数A(DefaultInit)导致将0分配给三个成员变量,而A(NoInit)导致根本没有代码。

struct B {
    std::atomic<long> a{1};
    std::atomic<long> b{2};
    int c{3};

    B() {} // This is fine.
    B(NoInit) : a(), b(), c() {} // Why setting to 0? Why should it generate any assignment code at all?

};

在第二个示例中,struct B&#39; B(NoInit)尝试显式调用std::atomic::atomic(),这将导致无store/mov条指令。但这会导致为所有三个变量分配0!

当然标准确实说它是未定义的行为,如果是这样,为什么A(DefaultInit)A(NoInit)之间存在差异。我希望B(NoInit)的汇编与A(NoInit)相同。

另外,请注意,在两种情况下,生成的程序集对于成员变量c都没有区别。这与std::atomic

无关

1 个答案:

答案 0 :(得分:2)

你不能真正“明确地调用构造函数”。您只能为对象指定初始值设定项,构造函数调用可以作为其中的一部分进行。我说作为其中的一部分,因为一个无害的初始化器可以传达比人们想象的更多的意义。在这种情况下:

B(NoInit) : a(), b(), c() {} 

初始值设定项()表示您value-initialize每个成员。值初始化需要首先零初始化(从C ++ 11开始)。虽然有时会涉及何时以及何种初始化的确切情况和条件,但您可以在链接的文章中阅读它们。

在您的特定情况下,对于std::atomic类型,会发生这种情况:

  

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

对于普通int,就是这样:

  

否则,该对象被零初始化。

最终会占到你看到的所有三个零。

如果你不想看到零初始化,你可以告诉两个选项。两者都是对初始化器规则的轻微利用:

  1. 省略初始化程序,这是最简单的。
  2. 将其包装在一个类型中,其值初始化调用用户提供的c'tor什么都不做(here it is working,但要完全支持原始代码需要更多的valueless_initialization样板