I find that in practice, with a variety of C++11/C++14 compilers, a std::atomic
has an undefined initial value just as it would if it were a "raw" type. That is, we expect that for the expression
int a;
a
may have any value. It also turns out to be true that for the expression
std::atomic< int > b;
b
may also have any value. To say it another way,
std::atomic< int > b; // b is undefined
is not equivalent to
std::atomic< int > b{ 0 }; // b == 0
or to
std::atomic< int > b{}; // b == 0
because in the latter two cases b
is initialized to a known value.
My question is simple: where in the C++11 or C++14 spec is this behavior documented?
[atomics.types.generic]/5 says this about integral specializations:
The atomic integral specializations and the specialization atomic shall have standard layout. They shall each have a trivial default constructor and a trivial destructor. They shall each support aggregate
initialization syntax.
Moreover, the primary template synopsis at the beginning of the same section normatively specifies the default constructor as:
atomic() noexcept = default;
The effects are defined in [atomic.types.operations]/4 as:
Effects: leaves the atomic object in an uninitialized state.
§ 29.6.5 [atomics.types.operations.req] ¶ 4 of N 4140 (the final draft for C++14) says:
A ::A () noexcept = default;
Effects: leaves the atomic object in an uninitialized state. [ Note: These semantics ensure compatibility with C. — end note ]
Note that this doesn't mean that the object wraps an unspecified value that you can read but not depend on its value. Rather, it means that reading the value out of the object before assigning to it results in undefined behavior.