By work在这里,我的意思是std::atomic<T> a{}
有效地进行零初始化a
。我一直这么想,并且一直在实际使用它,直到this。在解释我对此的理解之前,我想表明,至少 gcc 和 clang 正在实践中这样做。
#include <cstring>
#include <atomic>
#include <iostream>
int main() {
using atomic = std::atomic<int>;
auto p = (atomic*)operator new(sizeof(atomic));
std::memset(p, -1, sizeof(atomic));
new(p) atomic{};
std::cout << p->load() << std::endl;
}
输出是0
双方gcc and clang.
以下是我对为什么这应该有效的解释(当然,你可能不这么认为)。标准说
在以下操作定义中:
[...]
A::A() noexcept = default;
Effects:使原子对象处于未初始化状态。 [注:这些语义确保与 C 的兼容性。-尾注]
它基本上说默认构造函数是微不足道的,什么也不做。我对此表示同意,但我不明白这如何使值初始化变得不适用。根据cppref,值初始化的影响包括(强调我的):
如果 T 是一个类类型,其默认构造函数既不是
用户提供或删除(也就是说,它可能是一个带有
隐式定义或默认的默认构造函数),对象是
零初始化,然后如果它有一个则默认初始化
非平凡的默认构造函数;
std::atomic
有一个默认的默认构造函数,所以该对象是
- 零初始化,然后
- 如果它有一个重要的默认构造函数,则它是默认初始化的。
第 2 点在这里不适用,因为默认的默认构造函数很简单,但我没有看到任何使第 1 点无效的语句。我的理解正确还是我遗漏了什么?
最终,值初始化情况的关键在于[dcl.init]/7、项目符号 1 和 2:
对 T 类型的对象进行值初始化意味着:
- 如果 T 是具有用户提供的构造函数 ([class.ctor]) 的(可能是 cv 限定的)类类型 (Clause [class]),则使用默认构造函数
for T 被调用(如果 T 没有,则初始化是错误的
可访问的默认构造函数);
- T 是一个(可能是 cv 限定的)非联合类类型,没有用户提供的构造函数,则该对象是零初始化的,并且,如果
T 的隐式声明的默认构造函数并不简单,即
构造函数被调用。
- ...
应用上面两个项目中的哪一个取决于用户提供的 c'tor。我在其他答案的评论中不记得的是错综复杂的= default;
当应用于此时。如果我们看一下给出的定义[dcl.fct.def.默认]/4(强调我的):
显式默认函数和隐式声明函数是
统称为默认函数,并且实现应
为它们提供隐式定义([class.ctor] [class.dtor],
[class.copy]),这可能意味着将它们定义为已删除。一个特别的
如果成员函数是用户声明的而不是用户声明的,则该成员函数是用户提供的
明确默认或在第一次声明时删除。A
用户提供的显式默认函数(即显式
第一次声明后默认)定义在以下位置
它是明确默认的;如果这样的函数是隐式定义的
删除后,该程序格式不正确。 [ 注意:将函数声明为
第一次声明后默认可以提供高效的执行
和简洁的定义,同时启用稳定的二进制接口
不断发展的代码库。 ——尾注]
我们看到默认的c'toratomic
不是用户提供的,因为它被声明为默认,而不是先声明然后定义为默认。因此 [dcl.init]/7 的第二个项目符号是适用的,该对象被零初始化,然后是(非)调用(简单的默认)构造函数,该构造函数不执行任何操作。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)