By work here, I take to mean that std::atomic<T> a{}
effectively zero initializes a
. I have always been thinking so and have been practically using it until this. Before explaining my understanding of this, I want to show that, at the very least, gcc and clang are doing it in practice.
#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;
}
The output is 0
on both gcc and clang.
Following is my explanation of why this should work (you may think otherwise, of course). The standard says that
In the following operation definitions:
- an A refers to one of the atomic types.
[...]
A::A() noexcept = default;
Effects: leaves the atomic object in an uninitialized state. [ Note: These semantics ensure compatibility with C. — end note ]
It basically says that the default constructor is trivial and does nothing. I'm OK with this, but I don't see how this makes value initialization non-applicable. According to cppref, the effects of value initialization include (emphasis mine):
if T is a class type with a default constructor that is neither user-provided nor deleted (that is, it may be a class with an implicitly-defined or defaulted default constructor), the object is zero-initialized and then it is default-initialized if it has a non-trivial default constructor;
std::atomic
has a defaulted default constructor, so the object is
- zero-initialized and then
- it is default-initialized if it has a non-trivial default constructor.
Point 2 doesn't apply here since the defaulted default constructor is trivial, but I don't see any statement that renders point 1 in-effective. Is my understanding correct or am I missing something?
Ultimately the crux of the matter for the value initialization case is in [dcl.init]/7, bullets 1 and 2:
Which of the two bullets above is applied depends on the c'tor being user-provided. What I didn't remember in the comments to the other answer, is the intricacies of
= default;
when applied to that. If we look at the definition given at [dcl.fct.def.default]/4 (emphasis mine):We see that the default c'tor of
atomic
is not user provided, because it is declared as defaulted, as opposed to being declared and then defined as defaulted. So the second bullet of [dcl.init]/7 is applicable, the object is zero-initialized, followed by the (non-)invocation of the (trivial default) constructor which does nothing.