This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of CD1 status.
Section: 33.5.8 [atomics.types.generic] Status: CD1 Submitter: Alberto Ganesh Barbati Opened: 2007-12-28 Last modified: 2016-01-28
Priority: Not Prioritized
View all other issues in [atomics.types.generic].
View all issues with CD1 status.
Discussion:
in the latest publicly available draft, paper N2641, in section 33.5.8 [atomics.types.generic], the following specialization of the template atomic<> is provided for pointers:
template <class T> struct atomic<T*> : atomic_address { T* fetch_add(ptrdiff_t, memory_order = memory_order_seq_cst) volatile; T* fetch_sub(ptrdiff_t, memory_order = memory_order_seq_cst) volatile; atomic() = default; constexpr explicit atomic(T); atomic(const atomic&) = delete; atomic& operator=(const atomic&) = delete; T* operator=(T*) volatile; T* operator++(int) volatile; T* operator--(int) volatile; T* operator++() volatile; T* operator--() volatile; T* operator+=(ptrdiff_t) volatile; T* operator-=(ptrdiff_t) volatile; };
First of all, there is a typo in the non-default constructor which should take a T* rather than a T.
As you can see, the specialization redefine and therefore hide a few methods from the base class atomic_address, namely fetch_add, fetch_sub, operator=, operator+= and operator-=. That's good, but... what happened to the other methods, in particular these ones:
void store(T*, memory_order = memory_order_seq_cst) volatile; T* load( memory_order = memory_order_seq_cst ) volatile; T* swap( T*, memory_order = memory_order_seq_cst ) volatile; bool compare_swap( T*&, T*, memory_order, memory_order ) volatile; bool compare_swap( T*&, T*, memory_order = memory_order_seq_cst ) volatile;
By reading paper N2427 "C++ Atomic Types and Operations", I see that the definition of the specialization atomic<T*> matches the one in the draft, but in the example implementation the methods load(), swap() and compare_swap() are indeed present.
Strangely, the example implementation does not redefine the method store(). It's true that a T* is always convertible to void*, but not hiding the void* signature from the base class makes the class error-prone to say the least: it lets you assign pointers of any type to a T*, without any hint from the compiler.
Is there a true intent to remove them from the specialization or are they just missing from the definition because of a mistake?
[ Bellevue: ]
The proposed revisions are accepted.
Further discussion: why is the ctor labeled "constexpr"? Lawrence said this permits the object to be statically initialized, and that's important because otherwise there would be a race condition on initialization.
Proposed resolution:
Change the synopsis in 33.5.8 [atomics.types.generic]:
template <class T> struct atomic<T*> : atomic_address { void store(T*, memory_order = memory_order_seq_cst) volatile; T* load( memory_order = memory_order_seq_cst ) volatile; T* swap( T*, memory_order = memory_order_seq_cst ) volatile; bool compare_swap( T*&, T*, memory_order, memory_order ) volatile; bool compare_swap( T*&, T*, memory_order = memory_order_seq_cst ) volatile; T* fetch_add(ptrdiff_t, memory_order = memory_order_seq_cst) volatile; T* fetch_sub(ptrdiff_t, memory_order = memory_order_seq_cst) volatile; atomic() = default; constexpr explicit atomic(T*); atomic(const atomic&) = delete; atomic& operator=(const atomic&) = delete; T* operator=(T*) volatile; T* operator++(int) volatile; T* operator--(int) volatile; T* operator++() volatile; T* operator--() volatile; T* operator+=(ptrdiff_t) volatile; T* operator-=(ptrdiff_t) volatile; };