Title
LWG 3661 broke atomic<shared_ptr<T>> a; a = nullptr;
Status
wp
Section
[util.smartptr.atomic.shared]
Submitter
Zachary Wassall

Created on 2023-02-22.00:00:00 last changed 18 months ago

Messages

Date: 2023-06-19.14:50:03

Proposed resolution:

This wording is relative to N4928.

  1. Modify [util.smartptr.atomic.shared] as indicated:

    namespace std {
      template<class T> struct atomic<shared_ptr<T>> {
        […]
        constexpr atomic() noexcept;
        constexpr atomic(nullptr_t) noexcept : atomic() { }
        atomic(shared_ptr<T> desired) noexcept;
        atomic(const atomic&) = delete;
        void operator=(const atomic&) = delete;
        […]
        void operator=(shared_ptr<T> desired) noexcept;
        void operator=(nullptr_t) noexcept;
        […]
      private:
        shared_ptr<T> p; // exposition only
      };
    }
    
    […]
    void operator=(shared_ptr<T> desired) noexcept;
    

    -5- Effects: Equivalent to store(desired).

    void operator=(nullptr_t) noexcept;
    

    -?- Effects: Equivalent to store(nullptr).

Date: 2023-06-17.00:00:00

[ 2023-06-17 Approved at June 2023 meeting in Varna. Status changed: Voting → WP. ]

Date: 2023-03-15.00:00:00

[ 2023-03-22; Reflector poll ]

Set status to Tentatively Ready after six votes in favour during reflector poll.

Date: 2023-02-15.00:00:00

[ 2023-02-25; Daniel comments and provides wording ]

The suggested delegation below to store(nullptr) is not ambiguous and calls the constructor shared_ptr(nullptr_t), which is guaranteed to be no-throwing.

Date: 2023-02-22.00:00:00

LWG 3661, "constinit atomic<shared_ptr<T>> a(nullptr); should work" added the following to atomic<shared_ptr<T>>:

constexpr atomic(nullptr_t) noexcept : atomic() { }

I believe that doing so broke the following example:

atomic<shared_ptr<T>> a;
a = nullptr;

For reference, atomic<shared_ptr<T>> provides two assignment operator overloads:

void operator=(const atomic&) = delete;          // #1
void operator=(shared_ptr<T> desired) noexcept;  // #2

Prior to LWG 3661, the assignment in the example unambiguously matches #2. #1 is not viable because nullptr_t is not convertible to atomic<shared_ptr<T>>. After LWG 3611, #1 is viable and the assignment is ambiguous between #1 and #2.

I believe this could be remedied easily enough by adding an assignment operator to match the added nullptr_t constructor:

void operator=(nullptr_t) noexcept;
History
Date User Action Args
2023-06-19 14:50:03adminsetmessages: + msg13646
2023-06-19 14:50:03adminsetstatus: voting -> wp
2023-06-12 08:52:25adminsetstatus: ready -> voting
2023-03-22 22:32:33adminsetmessages: + msg13468
2023-03-22 22:32:33adminsetstatus: new -> ready
2023-02-25 15:13:55adminsetmessages: + msg13433
2023-02-25 15:13:55adminsetmessages: + msg13432
2023-02-22 00:00:00admincreate