ISO/IEC JTC1 SC22 WG14 N1484 – 2010-05-26
Lawrence Crowl, crowl@google.com
Paul E. McKenney, paulmck@linux.vnet.ibm.com
This document lists some additional errata in the specification of the atomics in the current working draft (n1425, along with proposed wording for their correction. It is based on n1477.
The list of errata is as follows:
It is not necessarily obvious that the C++ Working Draft wording implies that inclusion of atomics in a C-language union results in undefined behavior. This section therefore lists the statements in the C++ Working Draft that imply this conclusion, taken from an email from Lawrence.
Section 9.5p2 reads as follows:
A union can have member functions (including constructors and destructors), but not virtual (10.3) functions. A union shall not have base classes. A union shall not be used as a base class. If a union contains a non-static data member of reference type the program is ill-formed. At most one non-static data member of a union may have a brace-or-equal-initializer. [ Note: if any non-static data member of a union has a non-trivial default constructor (12.1), copy constructor (12.8), move constructor (12.8), copy assignment operator (12.8), move assignment operator (12.8), or destructor (12.4), the corresponding member function of the union must be user-provided or it will be implicitly deleted (8.4.3) for the union. — end note ]
This note elaborates the normative language found in Section 12.8p12:
An implicitly-declared copy/move constructor is an inline public member of its class. A defaulted copy/move constructor for a class X is defined as deleted (8.4.3) if X has:
— a variant member with a non-trivial corresponding constructor and X is a union-like class
In other words, if a member of the union has non-trivial copy constructors and non-trivial copy assignment operators, the user must supply the corresponding member function. However, the C language provides no way to supply such member functions.
Section 29.5.1 lists the following declarations for integral types:
atomic_bool(const atomic_bool&) = delete;
atomic_bool& operator=(const atomic_bool&) = delete;
atomic_bool& operator=(const atomic_bool&) volatile = delete;
Similar declaration appear for the other atomic types. These declarations imply that the atomic types have non-trivial copy constructors and non-trivial copy assignment operators. Therefore, placing atomics in C-language unions is forbidden, which we can model as undefined behavior.
This new paragraph notes that placing atomics in C-languages unions results in undefined behavior:
If a union contains an atomic object, undefined behavior ensues.
The example in this paragraph uses a function
atomic_compare_exchange()
that is not defined in this standard.
This needs to change to use atomic_compare_exchange_weak()
as shown below:
EXAMPLE: A consequence of spurious failure is that nearly all uses of weak compare-and-exchange will be in a loop.
expected = atomic_load(¤t);
do desired = function(expected);
while (!atomic_compare_exchange_weak(¤t, &expected, desired));
When a compare-and-exchange is in a loop, the weak version will yield better performance on some platforms. When a weak compare-and-exchange would require a loop and a strong one would not, the strong one is preferable.