>演示
首先是问题:我有一个带有默认构造函数的现有结构,该构造函数将其置于有效状态。我想要一个根本不进行初始化的 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
的B(NoInit)
尝试显式调用std::atomic::atomic()
,这应该不会导致store/mov
指令。但这会导致所有三个变量的赋值为 0!
当然,标准确实说它是未定义的行为,如果是这样,为什么A(DefaultInit)
和A(NoInit)
之间的区别。我希望B(NoInit)
的组装与A(NoInit)
相同。
另请注意,在这两种情况下,生成的程序集对于成员变量c
没有区别。这与std::atomic
无关
你不能真正"显式调用构造函数"。只能为对象指定初始值设定项,构造函数调用可以作为其中的一部分发生。我说是其中的一部分,因为一个无害的初始值设定项可以传达比人们想象的更多的意义。在这种情况下:
B(NoInit) : a(), b(), c() {}
初始值设定项()
意味着对每个成员进行值初始化。值初始化需要首先将其初始化为零(自 C++11 以来(。尽管何时以及发生初始化类型的确切情况和条件有些涉及,但您可以在链接的文章中阅读它们。
在您的特定情况下,对于std::atomic
类型,会发生以下情况:
如果
T
是具有默认构造函数的类类型,则既不是 用户提供或删除的(也就是说,它可能是一个具有 隐式定义或默认的默认构造函数(,对象是 零初始化,如果它有一个 非平凡的默认构造函数;
而对于普通int
,它是这样的:
否则,对象初始化为零。
这最终解释了你看到的所有三个零。
如果你想看不到零初始化,据我所知,你有两个选择。两者都是对初始值设定项规则的轻微利用:
- 省略初始值设定项,这是最简单的。
- 将其包装在值初始化调用用户提供的 c'tor 的类型中,该类型不执行任何操作(这里它正在工作,但要完全支持您的原始代码需要更多的样板
valueless_initialization
(。