By working here, I mean that std::atomic<T> a{} effectively zero initializes a . I always thought so and practically used it before. Before explaining my understanding of this, I want to show that at least gcc and clang do this 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; }
Pin 0 to gcc and clang .
Below is my explanation of why this should work (of course, you might think differently). The standard says that
In the following definitions of operations:
- a refers to one of the atomic types.
[...]
A::A() noexcept = default;
Effects: leaves the atomic object in an uninitialized state. [Note: these semantics provide compatibility with C. - end note]
It basically says that the default constructor is trivial and does nothing. I am fine with this, but I do not see how this makes initializing the value inapplicable. According to cppref , value initialization effects include (highlight mine):
if T is a class type with a default constructor that is not user-provided or remote (that is, it can be a class with an implicit or default default constructor ), the zero object is initialized, and then initialized by default if it has a non-trivial constructor default;
std::atomic has a standard default constructor, so the object
- with zero initialization and then
- it is initialized by default if it has a non-trivial default constructor.
Clause 2 does not apply here, since the standard default constructor is trivial, but I do not see any statements that make clause 1 invalid. Did I understand correctly or is something missing?