原子的 0 初始化是否保证将值成员设置为 0?

Is 0-initialization of atomics guaranteed to set the value member to 0?

std::atomic<integral_type>变量的0初始​​化是什么意思?

问题的来源。我有一个 std::atomic<std::int> 的静态函数 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
}

error: use of deleted function ‘std::atomic::atomic(const std::atomic&)’ std::array arr = {0, 0};

现在,我知道静态 std::array 将对其所有成员进行 0 初始化,而 std::atomic<> 将进行 0 初始化。但是我们是否有明确或隐含的保证,它实际上会将所有 values 设置为 0?常识说 'yes' - 毕竟,我们假设 class 会有一个 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 */

Demo。当省略大括号时,我们正在复制初始化,这需要创建一个临时文件并从中复制。有了大括号,我们有了复制列表初始化,它的作用与直接列表初始化相同(即用 {0} 初始化每个元素,这很好)。

您也可以等到 guaranteed copy elision 被引入,然后使用您的语法。

来自 cppreference,std::atomic 的默认构造函数的文档说:

Constructs new atomic variable.

1) The default constructor is trivial: no initialization takes place other than zero initialization of static and thread-local objects. std::atomic_init may be used to complete initialization.

所以你肯定需要 Columbo 的初始化循环。

你需要区分的是默认初始化和零初始化。前段时间我对这个话题很感兴趣,得出的结论是标准隐含地要求 atomic-class 在初始化时与结构相同。

非原子基类型需要简单可复制,原子类型需要既支持默认初始化又支持使用(和不使用)ATOMIC_VAR_INIT 进行静态初始化。 我想不出任何干净的解决方案,最终不会使用内部结构或从结构派生(我为内部 RT OS 编写了一个原子实现)。

因此,即使没有要求,标准也至少会高度引导实现朝着零初始化完全符合您要求的解决方案发展。

我做了一个 Live Example 比较了以下内容:

std::array<t, 2> default;
std::array<t, 2> zero{};
std::array<t, 2> explicit{{{0},{0}}};

您将看到零初始化与显式版本相同,并且 gcc 6.3.0 更加高效。

重申一下,我认为该标准并未明确要求零初始化才能以这种方式运行,但据我所知,鉴于定义的内容,它必须如此。