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: 32.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 32.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 32.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;
};