0-原子的初始化是否保证将值成员设置为0
Is 0-initialization of atomics guaranteed to set the value member to 0?
std::atomic<integral_type>
变量的0-初始化意味着什么?
问题的起源。我有一个std::atomic<std::int>
的函数static std::array
,我希望在第一次使用之前将其设置为0(不用说,数组所在的函数是以不可预测的方式从多个线程调用的)。
这段代码很好看,但由于原子是不可复制的,所以不能编译:
#include <array>
#include <atomic>
void foo() {
using t = std::atomic<int>;
static std::array<t, 2> arr = {0, 0}; // <-- explicit, but errors out (see below)
static std::array<t, 2> arr2; // <-- implicit?, works
}
错误:使用已删除的函数"std::atomic::atoic(const std::原子&)"std::array arr={0,0};
现在,我知道静态std::array
将0初始化它的所有成员,而std::atomic<>
将0初始化。但是,我们是否有明确或隐含的保证,它实际上会将所有值设置为0?常识说"是"——毕竟,我们假设类将有一个类型为int
的成员,并且该成员将被0初始化。但这一假设是否建立在坚实的标准基础之上?
使用(通常是冗余的)大括号来避免复制初始化:
static t arr[2] = {{0}, {0}};
static std::array<t, 2> arr2 = {{{0}, {0}}}; /* Need extra pair here; otherwise {0} is
treated as the initializer of the internal
array */
演示。当省略大括号时,我们正在进行复制初始化,这需要创建一个临时大括号并从中复制。使用大括号,我们可以进行复制列表初始化,其作用与直接列表初始化相同(即使用{0}
初始化每个元素,这很好)。
您也可以等到引入了有保证的副本省略后再使用您的语法。
需要区分的是默认初始化和零初始化。不久前,我对这个主题很感兴趣,并得出结论,标准隐含地要求原子类在初始化时与structs的行为相同。
非原子基类型需要具有普通的可复制性,并且原子类型需要同时支持默认初始化和使用(或不使用)ATOMIC_VAR_INIT
静态初始化。我没有任何干净的解决方案可以不使用内部结构或从结构派生(我为内部RTOS编写了一个原子实现)。
因此,如果没有要求的话,该标准至少会高度引导实现朝着零初始化完全符合您要求的解决方案发展。
我做了一个活生生的例子,比较了以下内容:
std::array<t, 2> default;
std::array<t, 2> zero{};
std::array<t, 2> explicit{{{0},{0}}};
您将看到零初始化与显式版本完全相同,并且使用gcc6.3.0更高效。
只是重申一下,我不认为标准明确要求零初始化才能实现这种行为,但据我所知,鉴于定义的内容,它必须如此。
从cppreference,std::atomic默认构造函数的文档说明:
构造新的原子变量。
1) 默认构造函数是琐碎的:除了静态和线程本地对象的零初始化之外,不进行任何初始化。std::atomic_init可以用来完成初始化。
所以你肯定需要Columbo的初始化循环。
- 嵌套在类中时无法设置成员数据
- 为什么将一个结构的引用设置为等于另一个结构只会更改一个数据成员?
- 聚合初始化,将成员指针设置为同一结构成员
- 是否可以使用智能指针成员设置具有另一个结构的结构?
- 将 AlphaMode 成员设置为 DXGI_SWAP_CHAIN_DESC1 会使 CreateSwapChainFo
- 如何为类中可能无法计算的成员设置值
- 在运行时为随机分布类成员设置最小和最大边界?
- 是否可以为模板类的模板函数成员设置别名?
- 将常量引用成员设置为临时变量是否安全
- 对象超出范围后,引用成员设置为 0
- 为 QWidget 的私有成员设置样式表
- 将CPP类成员设置为SQLite DB中的列
- 将数组的成员设置为零
- 0-原子的初始化是否保证将值成员设置为0
- 将公共成员设置为只读
- 在模板化结构的所有实例中将成员设置为相同的值
- 如何将类成员设置为常量
- 将从std::string派生的类派生的类的数据成员设置为值
- 将继承的成员设置为静态
- 在析构函数中将类成员设置为空