简体   繁体   English

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

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

What does 0-initialization of std::atomic<integral_type> variable mean? std::atomic<integral_type>变量的0初始​​化是什么意思?

Origins of the question. 问题的由来。 I have a function-static std::array of std::atomic<std::int> , which I want to be set to 0 before the first use (goes without saying, function where the array resides is called in unpredictable manner from multiple threads). 我有一个std::atomic<std::int>的函数静态std::array ,我想在第一次使用前将其设置为0(不用说,数组所在的函数以一种无法预测的方式从多线程)。

This piece of code is good-looking, but not compiling due to atomics being non-copy constructable: 这段代码看起来不错,但由于原子不可复制构造,因此无法编译:

#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 :: atomic :: atomic(const std :: atomic&)'std :: array arr = {0,0};

Now, I understand that static std::array is going to 0-initialize all it's members, and std::atomic<> is going to be 0-initialized. 现在,我了解到静态std::array将对其所有成员进行0初始化,而std::atomic<>将进行0初始化。 But do we have an explicit or implicit gurantee that it will actually set all values to 0? 但是,我们是否有明确或隐含的保证实际上会将所有设置为0? Common sense says 'yes' - after all, we assume the class would have a member of type int , and this member will be 0-initialized. 常识说“是”-毕竟,我们假定类将具有int类型的成员,并且该成员将被0初始化。 But is that assumption based on solid grounds of standard? 但是,该假设是否基于标准的坚实依据?

Use (normally redundant) braces to avoid copy-initialization: 使用(通常是多余的)花括号来避免复制初始化:

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 . 演示 When omitting the braces, we're copy-initializing, which necessitates a temporary being created and copied from. 当省略花括号时,我们正在复制初始化,这需要创建一个临时对象并从中复制。 With the braces, we have copy-list-initialization, which acts the same as direct-list-initialization (ie initializes each element with {0} , which is fine). 使用花括号,我们具有复制列表初始化,其作用与直接列表初始化相同(即,使用{0}初始化每个元素,这很好)。

You can also wait until guaranteed copy elision is introduced and just use your syntax. 您也可以等到引入保证的复制省略 ,然后使用语法。

What you need to differentiate is default-initialization and zero-initialization. 您需要区分的是默认初始化和零初始化。 I have red about this very topic some time ago, and came to the conclusion that the standard implicitly requires the atomic-class to act identical to structs when it comes to initialization. 不久前,我对这个话题有些不满,得出的结论是,该标准隐式地要求原子类在初始化时必须与结构完全相同。

The non-atomic base type needs to be trivially copy-able, and the atomic type needs to both support default initialization and being initialized statically with (and without) ATOMIC_VAR_INIT . 非原子基本类型必须是可微复制的,原子类型既需要支持默认初始化,又需要使用ATOMIC_VAR_INIT (和不使用)进行静态初始化。 There aren't any any clean solutions I could come up with that don't end up using an inner struct or a deriving from a struct (I wrote an atomic implementation for a in-house RT OS). 我没有能提供的任何干净解决方案,这些解决方案最终不会使用内部结构或从结构派生(我为内部RT OS编写了原子实现)。

So the standard if not requires, at least highly steers the implementation towards a solution where zero-initialization does exactly what you want. 因此,该标准(如果不需要)至少会高度指导实现方案向零初始化完全满足您的要求的解决方案。

I made a Live Example which compares the following: 我制作了一个实时示例 ,比较了以下内容:

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

you will see that zero initialization is identical to the explicit version, and with gcc 6.3.0 even more efficient. 您会看到零初始化与显式版本相同,并且在gcc 6.3.0中甚至更有效。

Just to reiterate, I don`t think the standard explicitly requires zero-initialization to behave that way, but - to my understanding - given what is defined it necessarily has to. 只是重申一下,我不认为该标准明确要求零初始化以这种方式起作用,但是-就我的理解-考虑到定义必定必须这样做。

From cppreference, documentation of the default constructor of std::atomic says: 从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. 1)默认构造函数是微不足道的:除了静态和线程本地对象的零初始化之外, 不进行任何初始化 std::atomic_init may be used to complete initialization. std :: atomic_init可以用于完成初始化。

So you will need Columbo's initialisation loop for sure. 因此,您肯定需要Columbo的初始化循环。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM