What is a safe way to initialize an std::atomic_flag
in a class constructor?
This question seems to be asking the same question I'm asking - except here the asker is complaining about a compiler problem.
My question relates to the C++ standard itself. According to this site, initializing an std::atomic_flag
using constructor initializer syntax is unspecified.
std::atomic_flag static_flag = ATOMIC_FLAG_INIT; // static initialization,
// guaranteed to be available during dynamic initialization of static objects.
int main()
{
std::atomic_flag automatic_flag = ATOMIC_FLAG_INIT; // guaranteed to work
// std::atomic_flag another_flag(ATOMIC_FLAG_INIT); // unspecified
}
Is this information correct? If so, I assume that:
struct Foo
{
Foo() : flag(ATOMIC_FLAG_INIT)
{ }
std::atomic_flag flag;
};
...is also unspecified. So, does this mean that we can't use an std::atomic_flag
as a member variable of a class? Or is it safe if we simple call std::atomic_flag::clear()
from within a class constructor?
The wording concerning use of ATOMIC_FLAG_INIT
has changed since N3337 to N3936 (the current C++14 draft). The former shows a possible usage, in a copy-initialization context, of the ATOMIC_FLAG_INIT
macro in an example, which are non-normative, and doesn't mention anything about uses within other initialization contexts.
N3936 clarifies the usage, and no longer lists the copy-initialization usage as an example, but as part of the description itself.
§29.7/4 [atomics.flag]
The macro
ATOMIC_FLAG_INIT
shall be defined in such a way that it can be used to initialize an object of typeatomic_flag
to the clear state. The macro can be used in the form:atomic_flag guard = ATOMIC_FLAG_INIT;
It is unspecified whether the macro can be used in other initialization contexts. For a complete static-duration object, that initialization shall be static. Unless initialized with
ATOMIC_FLAG_INIT
, it is unspecified whether anatomic_flag
object has an initial state of set or clear.
The rationale for these changes is discussed here.
So you're right that using the macro in the member initializer list cannot be relied upon. The solution is to use a non-static data member initializer, or brace-or-equal-initializer, to initialize the atomic_flag
. Then it will be initialized in a copy initialization context.
struct Foo
{
std::atomic_flag flag = ATOMIC_FLAG_INIT;
};
The actual text of the C++11 standard (well, N1570)'s definition of ATOMIC_FLAG_INIT
is
7.17.8 Atomic flag type and operations
...
The macro
ATOMIC_FLAG_INIT
may be used to initialize anatomic_flag
to the clear state. Anatomic_flag
that is not explicitly initialized withATOMIC_FLAG_INIT
is initially in an indeterminate state.EXAMPLE
atomic_flag guard = ATOMIC_FLAG_INIT;
The C++ standard uses the word initialize to refer generally to all the various ways that a variable can be given an initial value. As there is no further wording to the contrary, I read the intent as being that atomic_flag guard(ATOMIC_FLAG_INIT)
, and use of ATOMIC_FLAG_INIT
in constructor initializer lists, are also valid and not unspecified. I think the site you quote is reading too much into the single example. Examples in this standard are not normative, and in particular, that an example shows one way to do something does not mean that that is the only acceptable way to do it.
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