Title
The effects of std::swap are under-specified
Status
nad
Section
[utility.swap]
Submitter
Jan Schultke

Created on 2024-02-28.00:00:00 last changed 1 month ago

Messages

Date: 2024-03-15.13:46:17

Proposed resolution:

This wording is relative to N4971.

  1. Modify [utility.swap] as indicated:

    template<class T>
      constexpr void swap(T& a, T& b) noexcept(see below);
    

    -1- Constraints: is_move_constructible_v<T> is true and is_move_assignable_v<T> is true.

    -2-Preconditions: Type T meets the Cpp17MoveConstructible (Table 31) and Cpp17MoveAssignable (Table 33) requirements.

    -3- Effects: Exchanges values stored in two locations.Equivalent to:

    auto t(std::move(a));
    a = std::move(b);
    b = std::move(t);
    

    -4- Remarks: The exception specification is equivalent to: […]

Date: 2024-03-15.00:00:00

[ 2024-03-15; Reflector poll ]

Set status to Tentatively NAD Editorial after reflector poll.

Cpp17MoveConstructible require direct-init and copy-init to be semantically equivalent, so the different implementation techniques can only be observed by types which fail to meet the function's preconditions.

Replace the unusual "stored in two locations" wording editorially.

Date: 2024-02-28.00:00:00

Subclause [utility.swap] describes the effect of std::swap as follows:

Effects: Exchanges values stored in two locations.

This description is extremely vague. A possible implementation which complies with this wording is:

template<class T>
constexpr void swap(T&, T&) noexcept(/* ... */)
{
    int __x = 0, __y = 0;
    int __z = __x;
    __x = __y;
    __y = __z;
}

This exchanges values stored in two locations; namely in the locations of two objects with automatic storage duration within swap. Since this has no observable effect and complies, it is also valid to implement swap as follows:

template<class T>
constexpr void swap(T&, T&) noexcept(/* ... */) { }

Furthermore, there is implementation divergence. libc++ uses direct-initialization to construct a temporary T, but libstdc++ uses copy-initialization. For most types, this hopefully calls the same constructor, however, this is not universally true. The standard should specify in more detail what is meant to happen.

History
Date User Action Args
2024-03-15 13:46:17adminsetmessages: + msg14011
2024-03-15 13:46:17adminsetstatus: new -> nad
2024-03-03 10:00:14adminsetmessages: + msg13969
2024-02-28 00:00:00admincreate