29 Atomic operations library [atomics]

29.6 Class template atomic_­ref [atomics.ref.generic]

namespace std {
  template<class T> struct atomic_ref {
  private:
    T* ptr;             // exposition only
  public:
    using value_type = T;
    static constexpr bool is_always_lock_free = implementation-defined;
    static constexpr size_t required_alignment = implementation-defined;

    atomic_ref() = delete;
    atomic_ref& operator=(const atomic_ref&) = delete;

    explicit atomic_ref(T&);
    atomic_ref(const atomic_ref&) noexcept;

    T operator=(T) const noexcept;
    operator T() const noexcept;

    bool is_lock_free() const noexcept;
    void store(T, memory_order = memory_order_seq_cst) const noexcept;
    T load(memory_order = memory_order_seq_cst) const noexcept;
    T exchange(T, memory_order = memory_order_seq_cst) const noexcept;
    bool compare_exchange_weak(T&, T,
                               memory_order, memory_order) const noexcept;
    bool compare_exchange_strong(T&, T,
                                 memory_order, memory_order) const noexcept;
    bool compare_exchange_weak(T&, T,
                               memory_order = memory_order_seq_cst) const noexcept;
    bool compare_exchange_strong(T&, T,
                                 memory_order = memory_order_seq_cst) const noexcept;
  };
}
An atomic_­ref object applies atomic operations ([atomics.general]) to the object referenced by *ptr such that, for the lifetime ([basic.life]) of the atomic_­ref object, the object referenced by *ptr is an atomic object ([intro.races]).
The template argument for T shall be trivially copyable ([basic.types]).
The lifetime ([basic.life]) of an object referenced by *ptr shall exceed the lifetime of all atomic_­refs that reference the object.
While any atomic_­ref instances exist that reference the *ptr object, all accesses to that object shall exclusively occur through those atomic_­ref instances.
No subobject of the object referenced by atomic_­ref shall be concurrently referenced by any other atomic_­ref object.
Atomic operations applied to an object through a referencing atomic_­ref are atomic with respect to atomic operations applied through any other atomic_­ref referencing the same object.
[Note
:
Atomic operations or the atomic_­ref constructor could acquire a shared resource, such as a lock associated with the referenced object, to enable atomic operations to be applied to the referenced object.
end note
]

29.6.1 Operations [atomics.ref.operations]

static constexpr bool is_always_lock_free;
The static data member is_­always_­lock_­free is true if the atomic_­ref type's operations are always lock-free, and false otherwise.
static constexpr size_t required_alignment;
The alignment required for an object to be referenced by an atomic reference, which is at least alignof(T).
[Note
:
Hardware could require an object referenced by an atomic_­ref to have stricter alignment ([basic.align]) than other objects of type T.
Further, whether operations on an atomic_­ref are lock-free could depend on the alignment of the referenced object.
For example, lock-free operations on std::complex<double> could be supported only if aligned to 2*alignof(double).
end note
]
atomic_ref(T& obj);
Requires: The referenced object shall be aligned to required_­alignment.
Effects: Constructs an atomic reference that references the object.
Throws: Nothing.
atomic_ref(const atomic_ref& ref) noexcept;
Effects: Constructs an atomic reference that references the object referenced by ref.
T operator=(T desired) const noexcept;
Effects: Equivalent to:
store(desired);
return desired;
operator T() const noexcept;
Effects: Equivalent to: return load();
bool is_lock_free() const noexcept;
Returns: true if the object's operations are lock-free, false otherwise.
void store(T desired, memory_order order = memory_order_seq_cst) const noexcept;
Requires: The order argument shall not be memory_­order_­consume, memory_­order_­acquire, nor memory_­order_­acq_­rel.
Effects: Atomically replaces the value referenced by *ptr with the value of desired.
Memory is affected according to the value of order.
T load(memory_order order = memory_order_seq_cst) const noexcept;
Requires: The order argument shall not be memory_­order_­release nor memory_­order_­acq_­rel.
Effects: Memory is affected according to the value of order.
Returns: Atomically returns the value referenced by *ptr.
T exchange(T desired, memory_order order = memory_order_seq_cst) const noexcept;
Effects: Atomically replaces the value referenced by *ptr with desired.
Memory is affected according to the value of order.
This operation is an atomic read-modify-write operation ([intro.multithread]).
Returns: Atomically returns the value referenced by *ptr immediately before the effects.
bool compare_exchange_weak(T& expected, T desired, memory_order success, memory_order failure) const noexcept; bool compare_exchange_strong(T& expected, T desired, memory_order success, memory_order failure) const noexcept; bool compare_exchange_weak(T& expected, T desired, memory_order order = memory_order_seq_cst) const noexcept; bool compare_exchange_strong(T& expected, T desired, memory_order order = memory_order_seq_cst) const noexcept;
Requires: The failure argument shall not be memory_­order_­release nor memory_­order_­acq_­rel.
Effects: Retrieves the value in expected.
It then atomically compares the value referenced by *ptr for equality with that previously retrieved from expected, and if true, replaces the value referenced by *ptr with that in desired.
If and only if the comparison is true, memory is affected according to the value of success, and if the comparison is false, memory is affected according to the value of failure.
When only one memory_­order argument is supplied, the value of success is order, and the value of failure is order except that a value of memory_­order_­acq_­rel shall be replaced by the value memory_­order_­acquire and a value of memory_­order_­release shall be replaced by the value memory_­order_­relaxed.
If and only if the comparison is false then, after the atomic operation, the contents of the memory in expected are replaced by the value read from the value referenced by *ptr during the atomic comparison.
If the operation returns true, these operations are atomic read-modify-write operations ([intro.races]) on the value referenced by *ptr.
Otherwise, these operations are atomic load operations on that memory.
Returns: The result of the comparison.
Remarks: A weak compare-and-exchange operation may fail spuriously.
That is, even when the contents of memory referred to by expected and ptr are equal, it may return false and store back to expected the same memory contents that were originally there.
[Note
:
This spurious failure enables implementation of compare-and-exchange on a broader class of machines, e.g., load-locked store-conditional machines. A consequence of spurious failure is that nearly all uses of weak compare-and-exchange will be in a loop. 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.
end note
]

29.6.2 Specializations for integral types [atomics.ref.int]

There are specializations of the atomic_­ref class template for the integral types char, signed char, unsigned char, short, unsigned short, int, unsigned int, long, unsigned long, long long, unsigned long long, char16_­t, char32_­t, wchar_­t, and any other types needed by the typedefs in the header <cstdint>.
For each such type integral, the specialization atomic_­ref<integral> provides additional atomic operations appropriate to integral types.
[Note
:
For the specialization atomic_­ref<bool>, see [atomics.ref.generic].
end note
]
namespace std {
  template<> struct atomic_ref<integral> {
  private:
    integral* ptr;        // exposition only
  public:
    using value_type = integral;
    using difference_type = value_type;
    static constexpr bool is_always_lock_free = implementation-defined;
    static constexpr size_t required_alignment = implementation-defined;

    atomic_ref() = delete;
    atomic_ref& operator=(const atomic_ref&) = delete;

    explicit atomic_ref(integral&);
    atomic_ref(const atomic_ref&) noexcept;

    integral operator=(integral) const noexcept;
    operator integral() const noexcept;

    bool is_lock_free() const noexcept;
    void store(integral, memory_order = memory_order_seq_cst) const noexcept;
    integral load(memory_order = memory_order_seq_cst) const noexcept;
    integral exchange(integral,
                      memory_order = memory_order_seq_cst) const noexcept;
    bool compare_exchange_weak(integral&, integral,
                               memory_order, memory_order) const noexcept;
    bool compare_exchange_strong(integral&, integral,
                                 memory_order, memory_order) const noexcept;
    bool compare_exchange_weak(integral&, integral,
                               memory_order = memory_order_seq_cst) const noexcept;
    bool compare_exchange_strong(integral&, integral,
                                 memory_order = memory_order_seq_cst) const noexcept;

    integral fetch_add(integral,
                       memory_order = memory_order_seq_cst) const noexcept;
    integral fetch_sub(integral,
                       memory_order = memory_order_seq_cst) const noexcept;
    integral fetch_and(integral,
                       memory_order = memory_order_seq_cst) const noexcept;
    integral fetch_or(integral,
                      memory_order = memory_order_seq_cst) const noexcept;
    integral fetch_xor(integral,
                       memory_order = memory_order_seq_cst) const noexcept;

    integral operator++(int) const noexcept;
    integral operator--(int) const noexcept;
    integral operator++() const noexcept;
    integral operator--() const noexcept;
    integral operator+=(integral) const noexcept;
    integral operator-=(integral) const noexcept;
    integral operator&=(integral) const noexcept;
    integral operator|=(integral) const noexcept;
    integral operator^=(integral) const noexcept;
  };
}
Descriptions are provided below only for members that differ from the primary template.
The following operations perform arithmetic computations.
The key, operator, and computation correspondence is identified in Table 133.
integral fetch_key(integral operand, memory_order order = memory_order_seq_cst) const noexcept;
Effects: Atomically replaces the value referenced by *ptr with the result of the computation applied to the value referenced by *ptr and the given operand.
Memory is affected according to the value of order.
These operations are atomic read-modify-write operations ([intro.races]).
Returns: Atomically, the value referenced by *ptr immediately before the effects.
Remarks: For signed integer types, arithmetic is defined to use two's complement representation.
There are no undefined results.
integral operator op=(integral operand) const noexcept;
Effects: Equivalent to: return fetch_­key(operand) op operand;

29.6.3 Specializations for floating-point types [atomics.ref.float]

There are specializations of the atomic_­ref class template for the floating-point types float, double, and long double.
For each such type floating-point, the specialization atomic_­ref<floating-point> provides additional atomic operations appropriate to floating-point types.
namespace std {
  template<> struct atomic_ref<floating-point> {
  private:
    floating-point* ptr;  // exposition only
  public:
    using value_type = floating-point;
    using difference_type = value_type;
    static constexpr bool is_always_lock_free = implementation-defined;
    static constexpr size_t required_alignment = implementation-defined;

    atomic_ref() = delete;
    atomic_ref& operator=(const atomic_ref&) = delete;

    explicit atomic_ref(floating-point&);
    atomic_ref(const atomic_ref&) noexcept;

    floating-point operator=(floating-point) noexcept;
    operator floating-point() const noexcept;

    bool is_lock_free() const noexcept;
    void store(floating-point, memory_order = memory_order_seq_cst) const noexcept;
    floating-point load(memory_order = memory_order_seq_cst) const noexcept;
    floating-point exchange(floating-point,
                            memory_order = memory_order_seq_cst) const noexcept;
    bool compare_exchange_weak(floating-point&, floating-point,
                               memory_order, memory_order) const noexcept;
    bool compare_exchange_strong(floating-point&, floating-point,
                                 memory_order, memory_order) const noexcept;
    bool compare_exchange_weak(floating-point&, floating-point,
                               memory_order = memory_order_seq_cst) const noexcept;
    bool compare_exchange_strong(floating-point&, floating-point,
                                 memory_order = memory_order_seq_cst) const noexcept;

    floating-point fetch_add(floating-point,
                             memory_order = memory_order_seq_cst) const noexcept;
    floating-point fetch_sub(floating-point,
                             memory_order = memory_order_seq_cst) const noexcept;

    floating-point operator+=(floating-point) const noexcept;
    floating-point operator-=(floating-point) const noexcept;
  };
}
Descriptions are provided below only for members that differ from the primary template.
The following operations perform arithmetic computations.
The key, operator, and computation correspondence are identified in Table 133.
floating-point fetch_key(floating-point operand, memory_order order = memory_order_seq_cst) const noexcept;
Effects: Atomically replaces the value referenced by *ptr with the result of the computation applied to the value referenced by *ptr and the given operand.
Memory is affected according to the value of order.
These operations are atomic read-modify-write operations ([intro.races]).
Returns: Atomically, the value referenced by *ptr immediately before the effects.
Remarks: If the result is not a representable value for its type ([expr.pre]), the result is unspecified, but the operations otherwise have no undefined behavior.
Atomic arithmetic operations on floating-point should conform to the std::numeric_­limits<floating-point> traits associated with the floating-point type ([limits.syn]).
The floating-point environment ([cfenv]) for atomic arithmetic operations on floating-point may be different than the calling thread's floating-point environment.
floating-point operator op=(floating-point operand) const noexcept;
Effects: Equivalent to: return fetch_­key(operand) op operand;

29.6.4 Partial specialization for pointers [atomics.ref.pointer]

namespace std {
  template<class T> struct atomic_ref<T*> {
  private:
    T** ptr;              // exposition only
  public:
    using value_type = T*;
    using difference_type = ptrdiff_t;
    static constexpr bool is_always_lock_free = implementation-defined;
    static constexpr size_t required_alignment = implementation-defined;

    atomic_ref() = delete;
    atomic_ref& operator=(const atomic_ref&) = delete;

    explicit atomic_ref(T*&);
    atomic_ref(const atomic_ref&) noexcept;

    T* operator=(T*) const noexcept;
    operator T*() const noexcept;

    bool is_lock_free() const noexcept;
    void store(T*, memory_order = memory_order_seq_cst) const noexcept;
    T* load(memory_order = memory_order_seq_cst) const noexcept;
    T* exchange(T*, memory_order = memory_order_seq_cst) const noexcept;
    bool compare_exchange_weak(T*&, T*,
                               memory_order, memory_order) const noexcept;
    bool compare_exchange_strong(T*&, T*,
                                 memory_order, memory_order) const noexcept;
    bool compare_exchange_weak(T*&, T*,
                               memory_order = memory_order_seq_cst) const noexcept;
    bool compare_exchange_strong(T*&, T*,
                                 memory_order = memory_order_seq_cst) const noexcept;

    T* fetch_add(difference_type, memory_order = memory_order_seq_cst) const noexcept;
    T* fetch_sub(difference_type, memory_order = memory_order_seq_cst) const noexcept;

    T* operator++(int) const noexcept;
    T* operator--(int) const noexcept;
    T* operator++() const noexcept;
    T* operator--() const noexcept;
    T* operator+=(difference_type) const noexcept;
    T* operator-=(difference_type) const noexcept;
  };
}
Descriptions are provided below only for members that differ from the primary template.
The following operations perform arithmetic computations.
The key, operator, and computation correspondence is identified in Table 134.
T* fetch_key(difference_type operand, memory_order order = memory_order_seq_cst) const noexcept;
Requires: T shall be an object type, otherwise the program is ill-formed.
Effects: Atomically replaces the value referenced by *ptr with the result of the computation applied to the value referenced by *ptr and the given operand.
Memory is affected according to the value of order.
These operations are atomic read-modify-write operations ([intro.races]).
Returns: Atomically, the value referenced by *ptr immediately before the effects.
Remarks: The result may be an undefined address, but the operations otherwise have no undefined behavior.
T* operator op=(difference_type operand) const noexcept;
Effects: Equivalent to: return fetch_­key(operand) op operand;

29.6.5 Member operators common to integers and pointers to objects [atomics.ref.memop]

T* operator++(int) const noexcept;
Effects: Equivalent to: return fetch_­add(1);
T* operator--(int) const noexcept;
Effects: Equivalent to: return fetch_­sub(1);
T* operator++() const noexcept;
Effects: Equivalent to: return fetch_­add(1) + 1;
T* operator--(int) const noexcept;
Effects: Equivalent to: return fetch_­sub(1) - 1;