
On Sun, Jan 13, 2013 at 9:12 PM, Vicente J. Botet Escriba <vicente.botet@wanadoo.fr> wrote:
Le 13/01/13 16:16, Andrey Semashev a écrit :
once_flag must always be statically initialized, that's the key feature that allows call_once to be thread-safe. In C++03 this can only be guaranteed for POD types. C++11 also includes constant initialization into static initialization (i.e. when objects are initialized with constexpr constructors). All other objects are initialized during dynamic initialization, which is not thread-safe.
Thanks for clarifications, I understand your concern. The non-POD once_flag implementation can not be used for static once_flag instances in a thread safe mode. Just for curiosity, from where comes the restriction that once_flag must always be statically initialized? Could you point me to the standard?
The standard only contains once_flag since C++11, and as you quoted its definition, it uses constexpr default constructor. The fact that it results in static initialization is outlined in 3.6.2/2. As for C++03, I cannot point you to a particular paper that defines once_flag; this is a matter of each particular implementation. However, it is known that dynamic initialization is just as unsafe in C++03 as it is in C++11, even more unsafe WRT function-local statics. In 3.6.2/1 in C++03 it is stated that "Objects of POD types (3.9) with static storage duration initialized with constant expressions (5.19) shall be initialized before any dynamic initialization takes place.", so one (if not the only one) way to implement once_flag safely is to make it a POD type. One thing still concerns me though with the C++11 code. The standard specifies that once_flag as non-copyable. This is quite reasonable when once_flag is used as described by the standard. OTOH, Boost.Thread supports the following code for backward compatibility: static once_flag flag = BOOST_ONCE_INIT; which expands to: static once_flag flag = once_flag(); Technically, this invokes the default constructor and then the copy constructor. Compilers may be smart enough to optimize the copy away, which explains why it compiles. But I'm not quite sure this is still a constant initialization, especially considering the bug in clang (it defines implicit constructor without constexpr). To be on the safe side I would probably define a special explicit initializing constructor marked with constexpr so that the initialization could look like this: static once_flag flag = {0};