What does 0-initialization of std::atomic<integral_type>
variable mean?
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).
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};
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. But do we have an explicit or implicit gurantee that it will actually set all values to 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. 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 (i.e. initializes each element with {0}
, which is fine).
You can also wait until guaranteed copy elision is introduced and just use your syntax.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With