This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of New status.

3633. Atomics are copy constructible and copy assignable from volatile atomics

Section: 33.5 [atomics] Status: New Submitter: Wesley Maxey Opened: 2021-11-05 Last modified: 2022-01-29

Priority: 3

View all other issues in [atomics].

View all issues with New status.

Discussion:

The specification of atomic and atomic<T*> (in 33.5.8.1 [atomics.types.generic.general] and 33.5.8.5 [atomics.types.pointer]) explicitly deletes the following functions:

atomic(const atomic&) = delete;
atomic& operator=(const atomic&) = delete;
atomic& operator=(const atomic&) volatile = delete;

The intent is to make atomic objects not copyable, so that initializing an atomic object from another atomic, or assigning an atomic object with a value from another atomic, must be an explicit operation.

We also explicitly support volatile objects of types that are specializations of std::atomic; some of the functions that are vital for the support of volatile atomics are the following conversion operators:

operator T() const volatile noexcept; // for non-pointers
operator T*() const volatile noexcept; // for pointers

The presence of this conversion operator means that all the statements in the following piece of code compile successfully today, despite the deleted functions mentioned earlier:

volatile std::atomic<int> a;
volatile std::atomic<int> b(a);
std::atomic<int> c(a);
b = a;
c = a;

However, if a is not a volatile object, none of the last four lines compile.

[2022-01-29; Reflector poll]

Set priority to 3 after reflector poll.
This PR would allow

atomic<int> x, y = std::move(x);
because const volatile& doesn't bind to rvalues. It sounds like we'll need to delete both const volatile& and const volatile&&.

Proposed resolution:

This wording is relative to N4901.

  1. Modify 33.5.8.1 [atomics.types.generic.general], class template atomic synopsis, as indicated:

    […]
    atomic(const volatile atomic&) = delete;
    atomic& operator=(const volatile atomic&) = delete;
    atomic& operator=(const volatile atomic&) volatile = delete;
    […]
    
  2. Modify 33.5.8.3 [atomics.types.int], class template atomic<integral> specialization synopsis, as indicated:

    […]
    atomic(const volatile atomic&) = delete;
    atomic& operator=(const volatile atomic&) = delete;
    atomic& operator=(const volatile atomic&) volatile = delete;
    […]
    
  3. Modify 33.5.8.4 [atomics.types.float], class template atomic<floating-point> specialization synopsis, as indicated:

    […]
    atomic(const volatile atomic&) = delete;
    atomic& operator=(const volatile atomic&) = delete;
    atomic& operator=(const volatile atomic&) volatile = delete;
    […]
    
  4. Modify 33.5.8.5 [atomics.types.pointer], class template atomic<T*> partial specialization synopsis, as indicated:

    […]
    atomic(const volatile atomic&) = delete;
    atomic& operator=(const volatile atomic&) = delete;
    atomic& operator=(const volatile atomic&) volatile = delete;
    […]