This paper suggest changes to the Atomics operations Library to make broad use of noexcept. The paper addresses National Body comments CH 16 and GB 60.
Changes in this paper are restricted to chapter 29 (Atomic operations library).
All changes in this paper are relative to N3225
All atomic operations should be amended with noexcept with the exception of deleted operations. We have enumerated the changes but we could also just advise the editor to append noexcept to all operations except deleted operations.
We wish to thank Lawrence Crowl and Paul Mckenney for their comments.
1. Modify as follows:
namespace std { // 29.3, order and consistency enum memory_order; template <class T> T kill_dependency(T y) noexcept; ... // 29.6.1, general operations on atomic types template <class T> bool atomic_is_lock_free(const volatile atomic_type*) noexcept; template <class T> bool atomic_is_lock_free(const atomic_type*) noexcept; template <class T> void atomic_init(volatile atomic_type*, T) noexcept; template <class T> void atomic_init(atomic_type*, T) noexcept; template <class T> void atomic_store(volatile atomic_type*, T) noexcept; template <class T> void atomic_store(atomic_type*, T) noexcept; template <class T> void atomic_store_explicit(volatile atomic_type*, T, memory_order) noexcept; template <class T> void atomic_store_explicit(atomic_type*, T, memory_order) noexcept; template <class T> T atomic_load(const volatile atomic_type*) noexcept; template <class T> T atomic_load(const atomic_type*) noexcept; template <class T> T atomic_load_explicit(const volatile atomic_type*, memory_order) noexcept; template <class T> T atomic_load_explicit(const atomic_type*, memory_order) noexcept; template <class T> bool atomic_exchange(volatile atomic_type*, T) noexcept; template <class T> bool atomic_exchange(atomic_type*, T) noexcept; template <class T> bool atomic_exchange_explicit(volatile atomic_type*, T, memory_order) noexcept; template <class T> bool atomic_exchange_explicit(atomic_type*, T, memory_order) noexcept; template <class T> bool atomic_compare_exchange_weak(volatile atomic_type*, T*, T) noexcept; template <class T> bool atomic_compare_exchange_weak(atomic_type*, T*, T) noexcept; template <class T> bool atomic_compare_exchange_strong(volatile atomic_type*, T*, T) noexcept; template <class T> bool atomic_compare_exchange_strong(atomic_type*, T*, T) noexcept; template <class T> bool atomic_compare_exchange_weak_explicit(volatile atomic_type*, T*, T, memory_order, memory_order) noexcept; template <class T> bool atomic_compare_exchange_weak_explicit(atomic_type*, T*, T. memory_order, memory_order) noexcept; template <class T> bool atomic_compare)exchange_strong_explicit(volatile atomic_type*, T*, T, memory_order, memory_order) noexcept; template <class T> bool atomic_compare_exchange_strong_explicit(atomic_type*, T*, T, memory_order, memory_order) noexcept; // 29.6.2, templated operations on atomic types template <class T> T atomic_fetch_add(volatile atomic-type*, T) noexcept; template <class T> T atomic_fetch_add(atomic-type*, T) noexcept; template <class T> T atomic_fetch_add_explicit(volatile atomic-type*, T, memory_order) noexcept; template <class T> T atomic_fetch_add_explicit(atomic-type*, T, memory_order) noexcept; template <class T> T atomic_fetch_sub(volatile atomic-type*, T) noexcept; template <class T> T atomic_fetch_sub(atomic-type*, T) noexcept; template <class T> T atomic_fetch_sub_explicit(volatile atomic-type*, T, memory_order) noexcept; template <class T> T atomic_fetch_sub_explicit(atomic-type*, T, memory_order) noexcept; template <class T> T atomic_fetch_and(volatile atomic-type*, T) noexcept; template <class T> T atomic_fetch_and(atomic-type*, T) noexcept; template <class T> T atomic_fetch_and_explicit(volatile atomic-type*, T, memory_order) noexcept; template <class T> T atomic_fetch_and_explicit(atomic-type*, T, memory_order) noexcept; template <class T> T atomic_fetch_or(volatile atomic-type*, T) noexcept; template <class T> T atomic_fetch_or(atomic-type*, T) noexcept; template <class T> T atomic_fetch_or_explicit(volatile atomic-type*, T, memory_order) noexcept; template <class T> T atomic_fetch_or_explicit(atomic-type*, T, memory_order) noexcept; template <class T> T atomic_fetch_xor(volatile atomic-type*, T) noexcept; template <class T> T atomic_fetch_xor(atomic-type*, T) noexcept; template <class T> T atomic_fetch_xor_explicit(volatile atomic-type*, T, memory_order) noexcept; template <class T> T atomic_fetch_xor_explicit(atomic-type*, T, memory_order) noexcept; // 29.6.3, arithmetic operations on atomic types template <> integral atomic_fetch_add(volatile atomic-integral*, integral) noexcept; template <> integral atomic_fetch_add(atomic-integral*, integral) noexcept; template <> integral atomic_fetch_add_explicit(volatile atomic-integral*, integral, memory_order) noexcept; template <> integral atomic_fetch_add_explicit(atomic-integral*, integral, memory_order) noexcept; template <> integral atomic_fetch_sub(volatile atomic-integral*, integral) noexcept; template <> integral atomic_fetch_sub(atomic-integral*, integral) noexcept; template <> integral atomic_fetch_sub_explicit(volatile atomic-integral*, integral, memory_order) noexcept; template <> integral atomic_fetch_sub_explicit(atomic-integral*, integral, memory_order) noexcept; template <> integral atomic_fetch_and(volatile atomic-integral*, integral) noexcept; template <> integral atomic_fetch_and(atomic-integral*, integral) noexcept; template <> integral atomic_fetch_and_explicit(volatile atomic-integral*, integral, memory_order) noexcept; template <> integral atomic_fetch_and_explicit(atomic-integral*, integral, memory_order) noexcept; template <> integral atomic_fetch_or(volatile atomic-integral*, integral) noexcept; template <> integral atomic_fetch_or(atomic-integral*, integral) noexcept; template <> integral atomic_fetch_or_explicit(volatile atomic-integral*, integral, memory_order) noexcept; template <> integral atomic_fetch_or_explicit(atomic-integral*, integral, memory_order) noexcept; template <> integral atomic_fetch_xor(volatile atomic-integral*, integral) noexcept; template <> integral atomic_fetch_xor(atomic-integral*, integral) noexcept; template <> integral atomic_fetch_xor_explicit(volatile atomic-integral*, integral, memory_order) noexcept; template <> integral atomic_fetch_xor_explicit(atomic-integral*, integral, memory_order) noexcept; // 29.6.4, partial specializations for pointers template <class T> T* atomic_fetch_add(volatile atomic<T*>*, ptrdiff_t) noexcept; template <class T> T* atomic_fetch_add(atomic<T*>*, ptrdiff_t) noexcept; template <class T> T* atomic_fetch_add_explicit(volatile atomic<T*>*, ptrdiff_t, memory_order) noexcept; template <class T> T* atomic_fetch_add_explicit(atomic<T*>*, ptrdiff_t, memory_order) noexcept; template <class T> T* atomic_fetch_sub(volatile atomic<T*>*, ptrdiff_t) noexcept; template <class T> T* atomic_fetch_sub(atomic<T*>*, ptrdiff_t) noexcept; template <class T> T* atomic_fetch_sub_explicit(volatile atomic<T*>*, ptrdiff_t, memory_order) noexcept; template <class T> T* atomic_fetch_sub_explicit(atomic<T*>*, ptrdiff_t, memory_order) noexcept; // 29.6.5, initialization #define ATOMIC_VAR_INIT(value) see below // 29.7, flag type and operations struct atomic_flag; bool atomic_flag_test_and_set(volatile atomic_flag*) noexcept; bool atomic_flag_test_and_set(atomic_flag*) noexcept; bool atomic_flag_test_and_set_explicit(volatile atomic_flag*, memory_order) noexcept; bool atomic_flag_test_and_set_explicit(atomic_flag*, memory_order) noexcept; void atomic_flag_clear(volatile atomic_flag*) noexcept; void atomic_flag_clear(atomic_flag*) noexcept; void atomic_flag_clear_explicit(volatile atomic_flag*, memory_order) noexcept; void atomic_flag_clear_explicit(atomic_flag*, memory_order) noexcept; // 29.8, fences void atomic_thread_fence(memory_order) noexcept; void atomic_signal_fence(memory_order) noexcept; }
template <class T> T kill_dependency(T y) noexcept;
namespace std { template <class T> struct atomic { bool is_lock_free() const volatile noexcept; bool is_lock_free() const noexcept; void store(T, memory_order = memory_order_seq_cst) volatile noexcept; void store(T, memory_order = memory_order_seq_cst) noexcept; T load(memory_order = memory_order_seq_cst) const volatile noexcept; T load(memory_order = memory_order_seq_cst) const noexcept; operator T() const volatile noexcept; operator T() const noexcept; T exchange(T, memory_order = memory_order_seq_cst) volatile noexcept; T exchange(T, memory_order = memory_order_seq_cst) noexcept; bool compare_exchange_weak(T&, T, memory_order, memory_order) volatile noexcept; bool compare_exchange_weak(T&, T, memory_order, memory_order) noexcept; bool compare_exchange_strong(T&, T, memory_order, memory_order) volatile noexcept; bool compare_exchange_strong(T&, T, memory_order, memory_order) noexcept; bool compare_exchange_weak(T&, T, memory_order = memory_order_seq_cst) volatile noexcept; bool compare_exchange_weak(T&, T, memory_order = memory_order_seq_cst) noexcept; bool compare_exchange_strong(T&, T, memory_order = memory_order_seq_cst) volatile noexcept; bool compare_exchange_strong(T&, T, memory_order = memory_order_seq_cst) noexcept; atomic() noexcept = default; constexpr atomic(T) noexcept; atomic(const atomic&) = delete; atomic& operator=(const atomic&) = delete; atomic& operator=(const atomic&) volatile = delete; T operator=(T) volatile noexcept; T operator=(T) noexcept; }; template <> struct atomic<integral> { bool is_lock_free() const volatile noexcept; bool is_lock_free() const noexcept; void store(integral, memory_order = memory_order_seq_cst) volatile noexcept; void store(integral, memory_order = memory_order_seq_cst) noexcept; integral load(memory_order = memory_order_seq_cst) const volatile noexcept; integral load(memory_order = memory_order_seq_cst) const noexcept; operator integral() const volatile noexcept; operator integral() const noexcept; integral exchange(integral, memory_order = memory_order_seq_cst) volatile noexcept; integral exchange(integral, memory_order = memory_order_seq_cst) noexcept; bool compare_exchange_weak(integral&, integral, memory_order, memory_order) volatile noexcept; bool compare_exchange_weak(integral&, integral, memory_order, memory_order) noexcept; bool compare_exchange_strong(integral&, integral, memory_order, memory_order) volatile noexcept; bool compare_exchange_strong(integral&, integral, memory_order, memory_order) noexcept; bool compare_exchange_weak(integral&, integral, memory_order = memory_order_seq_cst) volatile noexcept; bool compare_exchange_weak(integral&, integral, memory_order = memory_order_seq_cst) noexcept; bool compare_exchange_strong(integral&, integral, memory_order = memory_order_seq_cst) volatile noexcept; bool compare_exchange_strong(integral&, integral, memory_order = memory_order_seq_cst) noexcept; integral fetch_add(integral, memory_order = memory_order_seq_cst) volatile noexcept; integral fetch_add(integral, memory_order = memory_order_seq_cst) noexcept; integral fetch_sub(integral, memory_order = memory_order_seq_cst) volatile noexcept; integral fetch_sub(integral, memory_order = memory_order_seq_cst) noexcept; integral fetch_and(integral, memory_order = memory_order_seq_cst) volatile noexcept; integral fetch_and(integral, memory_order = memory_order_seq_cst) noexcept; integral fetch_or(integral, memory_order = memory_order_seq_cst) volatile noexcept; integral fetch_or(integral, memory_order = memory_order_seq_cst) noexcept; integral fetch_xor(integral, memory_order = memory_order_seq_cst) volatile noexcept; integral fetch_xor(integral, memory_order = memory_order_seq_cst) noexcept; atomic() noexcept = default; constexpr atomic(integral) noexcept; atomic(const atomic&) = delete; atomic& operator=(const atomic&) = delete; atomic& operator=(const atomic&) volatile = delete; integral operator=(integral) volatile noexcept; integral operator=(integral) noexcept; integral operator++(int) volatile noexcept; integral operator++(int) noexcept; integral operator--(int) volatile noexcept; integral operator--(int) noexcept; integral operator++() volatile noexcept; integral operator++() noexcept; integral operator--() volatile noexcept; integral operator--() noexcept; integral operator+=(integral) volatile noexcept; integral operator+=(integral) noexcept; integral operator-=(integral) volatile noexcept; integral operator-=(integral) noexcept; integral operator&=(integral) volatile noexcept; integral operator&=(integral) noexcept; integral operator|=(integral) volatile noexcept; integral operator|=(integral) noexcept; integral operator^=(integral) volatile noexcept; integral operator^=(integral) noexcept; }; template <class T> struct atomic<T*> { bool is_lock_free() const volatile noexcept; bool is_lock_free() const noexcept; void store(T*, memory_order = memory_order_seq_cst) volatile noexcept; void store(T*, memory_order = memory_order_seq_cst) noexcept; T* load(memory_order = memory_order_seq_cst) const volatile noexcept; T* load(memory_order = memory_order_seq_cst) const noexcept; operator T*() const volatile noexcept; operator T*() const noexcept; T* exchange(T*, memory_order = memory_order_seq_cst) volatile noexcept; T* exchange(T*, memory_order = memory_order_seq_cst) noexcept; bool compare_exchange_weak(T*&, T*, memory_order, memory_order) volatile noexcept; bool compare_exchange_weak(T*&, T*, memory_order, memory_order) noexcept; bool compare_exchange_strong(T*&, T*, memory_order, memory_order) volatile noexcept; bool compare_exchange_strong(T*&, T*, memory_order, memory_order) noexcept; bool compare_exchange_weak(T*&, T*, memory_order = memory_order_seq_cst) volatile noexcept; bool compare_exchange_weak(T*&, T*, memory_order = memory_order_seq_cst) noexcept; bool compare_exchange_strong(T*&, T*, memory_order = memory_order_seq_cst) volatile noexcept; bool compare_exchange_strong(T*&, T*, memory_order = memory_order_seq_cst) noexcept; T* fetch_add(ptrdiff_t, memory_order = memory_order_seq_cst) volatile noexcept; T* fetch_add(ptrdiff_t, memory_order = memory_order_seq_cst) noexcept; T* fetch_sub(ptrdiff_t, memory_order = memory_order_seq_cst) volatile noexcept; T* fetch_sub(ptrdiff_t, memory_order = memory_order_seq_cst) noexcept; atomic() noexcept = default; constexpr atomic(T*) noexcept; atomic(const atomic&) = delete; atomic& operator=(const atomic&) = delete; atomic& operator=(const atomic&) volatile = delete; T* operator=(T*) volatile noexcept; T* operator=(T*) noexcept; T* operator++(int) volatile noexcept; T* operator++(int) noexcept; T* operator--(int) volatile noexcept; T* operator--(int) noexcept; T* operator++() volatile noexcept; T* operator++() noexcept; T* operator--() volatile noexcept; T* operator--() noexcept; T* operator+=(ptrdiff_t) volatile noexcept; T* operator+=(ptrdiff_t) noexcept; T* operator-=(ptrdiff_t) volatile noexcept; T* operator-=(ptrdiff_t) noexcept; }; }
A::A() noexcept = default;After p. 4, modify as follows
constexpr A::A(C desired) noexcept;After p. 6, modify as follows
bool atomic_is_lock_free(const volatile A *object) noexcept; bool atomic_is_lock_free(const A *object) noexcept; bool A::is_lock_free() const volatile noexcept; bool A::is_lock_free() const noexcept;After p. 7, modify as follows:
void atomic_init(volatile A *object, C desired) noexcept; void atomic_init(A *object, C desired) noexcept;After p. 8, modify as follows:
void atomic_store(volatile A* object, C desired) noexcept; void atomic_store(A* object, C desired) noexcept; void atomic_store_explicit(volatile A *object, C desired, memory_order order) noexcept; void atomic_store_explicit(A* object, C desired, memory_order order) noexcept; void A::store(C desired, memory_order order = memory_order_seq_cst) volatile noexcept; void A::store(C desired, memory_order order = memory_order_seq_cst) noexcept;After p. 10, modify as follows:
C A::operator=(C desired) volatile noexcept; C A::operator=(C desired) noexcept;After p. 12, modify as follows:
C atomic_load(const volatile A* object) noexcept; C atomic_load(const A* object) noexcept; C atomic_load_explicit(const volatile A* object, memory_order) noexcept; C atomic_load_explicit(const A* object, memory_order) noexcept; C A::load(memory_order order = memory_order_seq_cst) const volatile noexcept; C A::load(memory_order order = memory_order_seq_cst) const noexcept;After p. 15, modify as follows:
A::operator C () const volatile noexcept; A::operator C () const noexcept;After p. 17, modify as follows:
C atomic_exchange(volatile A* object, C desired) noexcept; C atomic_exchange(A* object, C desired) noexcept; C atomic_exchange_explicit(volatile A* object, C desired, memory_order) noexcept; C atomic_exchange_explicit(A* object, C desired, memory_order) noexcept; C A::exchange(C desired, memory_order order = memory_order_seq_cst) volatile noexcept; C A::exchange(C desired, memory_order order = memory_order_seq_cst) noexcept;After p. 19, modify as follows:
bool atomic_compare_exchange_weak(volatile A* object, C * expected, C desired) noexcept; bool atomic_compare_exchange_weak(A* object, C * expected, C desired) noexcept; bool atomic_compare_exchange_strong(volatile A* object, C * expected, C desired) noexcept; bool atomic_compare_exchange_strong(A* object, C * expected, C desired) noexcept; bool atomic_compare_exchange_weak_explicit(volatile A* object, C * expected, C desired, memory_order success, memory_order failure) noexcept; bool atomic_compare_exchange_weak_explicit(A* object, C * expected, C desired, memory_order success, memory_order failure) noexcept; bool atomic_compare_exchange_strong_explicit(volatile A* object, C * expected, C desired, memory_order success, memory_order failure) noexcept; bool atomic_compare_exchange_strong_explicit(A* object, C * expected, C desired, memory_order success, memory_order failure) noexcept; bool A::compare_exchange_weak(C & expected, C desired, memory_order success, memory_order failure) volatile noexcept; bool A::compare_exchange_weak(C & expected, C desired, memory_order success, memory_order failure) noexcept; bool A::compare_exchange_strong(C & expected, C desired, memory_order success, memory_order failure) volatile noexcept; bool A::compare_exchange_strong(C & expected, C desired, memory_order success, memory_order failure) noexcept; bool A::compare_exchange_weak(C & expected, C desired, memory_order order = memory_order_seq_cst) volatile noexcept; bool A::compare_exchange_weak(C & expected, C desired, memory_order order = memory_order_seq_cst) noexcept; bool A::compare_exchange_strong(C & expected, C desired, memory_order order = memory_order_seq_cst) volatile noexcept; bool A::compare_exchange_strong(C & expected, C desired, memory_order order = memory_order_seq_cst) noexcept;Before p. 28, modify as follows:
C atomic_fetch_key(volatile A *object, M operand) noexcept; C atomic_fetch_key(A* object, M operand) noexcept; C atomic_fetch_key_explicit(volatile A *object, M operand, memory_order order) noexcept; C atomic_fetch_key_explicit(A* object, M operand, memory_order order) noexcept; C A::fetch_key(M operand, memory_order order = memory_order_seq_cst) volatile noexcept; C A::fetch_key(M operand, memory_order order = memory_order_seq_cst) noexcept;After p. 30, modify as follows:
C A::operator op=(M operand) volatile noexcept; C A::operator op=(M operand) noexcept;After p. 32, modify as follows:
C A::operator++(int) volatile noexcept; C A::operator++(int) noexcept;After p. 33, modify as follows:
C A::operator--(int) volatile noexcept; C A::operator--(int) noexcept;After p. 34, modify as follows:
C A::operator++() volatile noexcept; C A::operator++() noexcept;After p. 36, modify as follows:
C A::operator--() volatile noexcept; C A::operator--() noexcept;
namespace std { typedef struct atomic_flag { bool test_and_set(memory_order = memory_order_seq_cst) volatile noexcept; bool test_and_set(memory_order = memory_order_seq_cst) noexcept; void clear(memory_order = memory_order_seq_cst) volatile noexcept; void clear(memory_order = memory_order_seq_cst) noexcept; atomic_flag() noexcept = default; atomic_flag(const atomic_flag&) = delete; atomic_flag& operator=(const atomic_flag&) = delete; atomic_flag& operator=(const atomic_flag&) volatile = delete; } atomic_flag; bool atomic_flag_test_and_set(volatile atomic_flag*) noexcept; bool atomic_flag_test_and_set(atomic_flag*) noexcept; bool atomic_flag_test_and_set_explicit(volatile atomic_flag*, memory_order) noexcept; bool atomic_flag_test_and_set_explicit(atomic_flag*, memory_order) noexcept; void atomic_flag_clear(volatile atomic_flag*) noexcept; void atomic_flag_clear(atomic_flag*) noexcept; void atomic_flag_clear_explicit(volatile atomic_flag*, memory_order) noexcept; void atomic_flag_clear_explicit(atomic_flag*, memory_order) noexcept; #define ATOMIC_FLAG_INIT see below }After p. 4, modify as follows:
bool atomic_flag_test_and_set(volatile atomic_flag *object) noexcept; bool atomic_flag_test_and_set(atomic_flag *object) noexcept; bool atomic_flag_test_and_set_explicit(volatile atomic_flag *object, memory_order order) noexcept; bool atomic_flag_test_and_set_explicit(atomic_flag *object, memory_order order) noexcept; bool atomic_flag::test_and_set(memory_order order = memory_order_seq_cst) volatile noexcept; bool atomic_flag::test_and_set(memory_order order = memory_order_seq_cst) noexcept;After p. 6, modify as follows:
void atomic_flag_clear(volatile atomic_flag *object) noexcept; void atomic_flag_clear(atomic_flag *object) noexcept; void atomic_flag_clear_explicit(volatile atomic_flag *object, memory_order order) noexcept; void atomic_flag_clear_explicit(atomic_flag *object, memory_order order) noexcept; void atomic_flag::clear(memory_order order = memory_order_seq_cst) volatile noexcept; void atomic_flag::clear(memory_order order = memory_order_seq_cst) noexcept;
void atomic_thread_fence(memory_order order) noexcept;After p. 5, modify as follows:
void atomic_signal_fence(memory_order order) noexcept;