Difference between revisions of "cpp/algorithm/swap"
(+ array swap) |
YexuanXiao (Talk | contribs) m |
||
(71 intermediate revisions by 21 users not shown) | |||
Line 1: | Line 1: | ||
{{cpp/title|swap}} | {{cpp/title|swap}} | ||
− | {{cpp/algorithm/ | + | {{cpp/algorithm/navbar}} |
− | {{ | + | {{dcl begin}} |
− | {{ | + | {{dcl header|algorithm|notes={{mark until c++11}}}} |
− | {{ | + | {{dcl header|utility|notes={{mark since c++11}}}} |
+ | {{dcl header|string_view}} | ||
+ | {{dcl|num=1|notes={{mark|conditionally noexcept since C++11}}<br>{{mark constexpr since c++20}}|1= | ||
template< class T > | template< class T > | ||
void swap( T& a, T& b ); | void swap( T& a, T& b ); | ||
}} | }} | ||
− | {{ | + | {{dcl|num=2|notes={{mark|conditionally noexcept since C++11}}<br>{{mark constexpr since c++20}}|1= |
− | template< class | + | template< class T2, std::size_t N > |
− | void swap( | + | void swap( T2 (&a)[N], T2 (&b)[N] ); |
}} | }} | ||
− | {{ | + | {{dcl end}} |
Exchanges the given values. | Exchanges the given values. | ||
− | 1 | + | @1@ Swaps the values {{c|a}} and {{c|b}}. |
+ | {{rrev|since=c++17| | ||
+ | {{cpp/enable if|{{c|std::is_move_constructible_v<T> && std::is_move_assignable_v<T>}} is {{c|true}}}}. | ||
+ | }} | ||
− | 2 | + | @2@ Swaps the arrays {{c|a}} and {{c|b}}. Equivalent to {{c|std::swap_ranges(a, a + N, b)}}. |
+ | {{rrev|since=c++17| | ||
+ | {{cpp/enable if|{{c|std::is_swappable_v<T2>}} is {{c|true}}}}. | ||
+ | }} | ||
===Parameters=== | ===Parameters=== | ||
− | {{ | + | {{par begin}} |
− | {{ | + | {{par|a, b|the values to be swapped}} |
− | {{ | + | {{par hreq}} |
+ | {{par req|{{tt|T}} must meet the requirements of {{rev inl|until=c++11|{{named req|CopyConstructible}} and {{named req|CopyAssignable}}}}{{rev inl|since=c++11|{{named req|MoveConstructible}} and {{named req|MoveAssignable}}}}.}} | ||
+ | {{par req named|T2|Swappable}} | ||
+ | {{par end}} | ||
===Return value=== | ===Return value=== | ||
− | + | (none) | |
===Exceptions=== | ===Exceptions=== | ||
− | 1) {{noexcept| | + | @1@ {{rrev multi|until1=c++11 |
− | std::is_nothrow_move_constructible< | + | |rev1=(none) |
− | std::is_nothrow_move_assignable< | + | |rev2= |
− | )}} | + | {{noexcept| |
+ | std::is_nothrow_move_constructible<T>::value && | ||
+ | std::is_nothrow_move_assignable<T>::value | ||
+ | }} | ||
+ | }} | ||
+ | @2@ {{rrev multi|since1=c++11|rev1= | ||
+ | {{noexcept|noexcept(swap(*a, *b))}} The lookup for the identifier {{tt|swap}} in the exception specification finds this function template in addition to anything found by the usual lookup rules, making the exception specification equivalent to C++17 {{lc|std::is_nothrow_swappable}}. | ||
+ | |since2=c++17|rev2={{noexcept|std::is_nothrow_swappable_v<T2>}} | ||
+ | }} | ||
− | 2) {{ | + | ===Complexity=== |
+ | @1@ Constant. | ||
+ | |||
+ | @2@ Linear in {{c|N}}. | ||
+ | |||
+ | ===Specializations=== | ||
+ | {{rrev|until=c++20| | ||
+ | {{tt|std::swap}} may be [[cpp/language/extending std|specialized in namespace std]] for program-defined types, but such specializations are not found by [[cpp/language/adl|ADL]] (the namespace std is not the associated namespace for the program-defined type). | ||
+ | }} | ||
+ | The expected way to make a {{lsd|cpp/language/type#Program-defined type}} swappable is to provide a non-member function swap in the same namespace as the type: see {{named req|Swappable}} for details. | ||
+ | |||
+ | The following overloads are already provided by the standard library: | ||
+ | {{dsc begin}} | ||
+ | {{dsc inc|cpp/utility/pair/dsc swap2}} | ||
+ | {{dsc inc|cpp/utility/tuple/dsc swap2}} | ||
+ | {{dsc inc|cpp/memory/shared_ptr/dsc swap2}} | ||
+ | {{dsc inc|cpp/memory/weak_ptr/dsc swap2}} | ||
+ | {{dsc inc|cpp/memory/unique_ptr/dsc swap2}} | ||
+ | {{dsc inc|cpp/utility/functional/function/dsc swap2}} | ||
+ | {{dsc inc|cpp/string/basic_string/dsc swap2}} | ||
+ | {{dsc inc|cpp/container/dsc swap2|array}} | ||
+ | {{dsc inc|cpp/container/dsc swap2|deque}} | ||
+ | {{dsc inc|cpp/container/dsc swap2|forward_list}} | ||
+ | {{dsc inc|cpp/container/dsc swap2|list}} | ||
+ | {{dsc inc|cpp/container/dsc swap2|vector}} | ||
+ | {{dsc inc|cpp/container/dsc swap2|map}} | ||
+ | {{dsc inc|cpp/container/dsc swap2|multimap}} | ||
+ | {{dsc inc|cpp/container/dsc swap2|set}} | ||
+ | {{dsc inc|cpp/container/dsc swap2|multiset}} | ||
+ | {{dsc inc|cpp/container/dsc swap2|unordered_map}} | ||
+ | {{dsc inc|cpp/container/dsc swap2|unordered_multimap}} | ||
+ | {{dsc inc|cpp/container/dsc swap2|unordered_set}} | ||
+ | {{dsc inc|cpp/container/dsc swap2|unordered_multiset}} | ||
+ | {{dsc inc|cpp/container/dsc swap2|queue}} | ||
+ | {{dsc inc|cpp/container/dsc swap2|priority_queue}} | ||
+ | {{dsc inc|cpp/container/dsc swap2|stack}} | ||
+ | {{dsc inc|cpp/numeric/valarray/dsc swap2}} | ||
+ | {{dsc inc|cpp/io/basic_stringbuf/dsc swap2}} | ||
+ | {{dsc inc|cpp/io/basic_stringstream/dsc swap2|basic_istringstream}} | ||
+ | {{dsc inc|cpp/io/basic_stringstream/dsc swap2|basic_ostringstream}} | ||
+ | {{dsc inc|cpp/io/basic_stringstream/dsc swap2|basic_stringstream}} | ||
+ | {{dsc inc|cpp/io/basic_filebuf/dsc swap2}} | ||
+ | {{dsc inc|cpp/io/basic_fstream/dsc swap2|basic_ifstream}} | ||
+ | {{dsc inc|cpp/io/basic_fstream/dsc swap2|basic_ofstream}} | ||
+ | {{dsc inc|cpp/io/basic_fstream/dsc swap2|basic_fstream}} | ||
+ | {{dsc inc|cpp/io/basic_syncbuf/dsc swap2}} | ||
+ | {{dsc inc|cpp/io/basic_spanbuf/dsc swap2}} | ||
+ | {{dsc inc|cpp/io/basic_spanstream/dsc swap2|basic_ispanstream}} | ||
+ | {{dsc inc|cpp/io/basic_spanstream/dsc swap2|basic_ospanstream}} | ||
+ | {{dsc inc|cpp/io/basic_spanstream/dsc swap2|basic_spanstream}} | ||
+ | {{dsc inc|cpp/regex/basic_regex/dsc swap2}} | ||
+ | {{dsc inc|cpp/regex/match_results/dsc swap2}} | ||
+ | {{dsc inc|cpp/thread/thread/dsc swap2|thread}} | ||
+ | {{dsc inc|cpp/thread/unique_lock/dsc swap2}} | ||
+ | {{dsc inc|cpp/thread/shared_lock/dsc swap2}} | ||
+ | {{dsc inc|cpp/thread/promise/dsc swap2}} | ||
+ | {{dsc inc|cpp/thread/packaged_task/dsc swap2}} | ||
+ | {{dsc inc|cpp/utility/optional/dsc swap2}} | ||
+ | {{dsc inc|cpp/utility/any/dsc swap2}} | ||
+ | {{dsc inc|cpp/utility/variant/dsc swap2}} | ||
+ | {{dsc inc|cpp/utility/basic_stacktrace/dsc swap2}} | ||
+ | {{dsc inc|cpp/filesystem/path/dsc swap2}} | ||
+ | {{dsc inc|cpp/utility/expected/dsc swap2}} | ||
+ | {{dsc inc|cpp/thread/thread/dsc swap2|jthread}} | ||
+ | {{dsc inc|cpp/utility/functional/move_only_function/dsc swap2}} | ||
+ | {{dsc inc|cpp/thread/stop_source/dsc swap2}} | ||
+ | {{dsc inc|cpp/thread/stop_token/dsc swap2}} | ||
+ | <!--TODOs: | ||
+ | swap(std::flat_map) | ||
+ | swap(std::flat_set) | ||
+ | swap(std::flat_multimap) | ||
+ | swap(std::flat_multiset) | ||
+ | swap(std::unexpected) | ||
+ | swap(std::mdspan) | ||
+ | --> | ||
+ | {{dsc end}} | ||
===Example=== | ===Example=== | ||
− | {{example | + | {{example |
− | + | |<!-- should demo proper use of swap with generic types, as in void swap(T& other) {using std::swap; swap(member, other.member);} , not just trivialities --> | |
− | + | |code= | |
+ | #include <algorithm> | ||
+ | #include <iostream> | ||
− | + | namespace Ns | |
+ | { | ||
+ | class A | ||
+ | { | ||
+ | int id {}; | ||
+ | |||
+ | friend void swap(A& lhs, A& rhs) | ||
+ | { | ||
+ | std::cout << "swap(" << lhs << ", " << rhs << ")\n"; | ||
+ | std::swap(lhs.id, rhs.id); | ||
+ | } | ||
+ | |||
+ | friend std::ostream& operator<<(std::ostream& os, A const& a) | ||
+ | { | ||
+ | return os << "A::id=" << a.id; | ||
+ | } | ||
+ | |||
+ | public: | ||
+ | A(int i) : id {i} {} | ||
+ | A(A const&) = delete; | ||
+ | A& operator = (A const&) = delete; | ||
+ | }; | ||
+ | } | ||
+ | int main() | ||
+ | { | ||
+ | int a = 5, b = 3; | ||
+ | std::cout << a << ' ' << b << '\n'; | ||
+ | std::swap(a, b); | ||
+ | std::cout << a << ' ' << b << '\n'; | ||
+ | |||
+ | Ns::A p {6}, q {9}; | ||
+ | std::cout << p << ' ' << q << '\n'; | ||
+ | // std::swap(p, q); // error, type requirements are not satisfied | ||
+ | swap(p, q); // OK, ADL finds the appropriate friend `swap` | ||
+ | std::cout << p << ' ' << q << '\n'; | ||
+ | } | ||
+ | |output= | ||
+ | 5 3 | ||
+ | 3 5 | ||
+ | A::id=6 A::id=9 | ||
+ | swap(A::id=6, A::id=9) | ||
+ | A::id=9 A::id=6 | ||
}} | }} | ||
− | === | + | ===Defect reports=== |
− | {{ | + | {{dr list begin}} |
+ | {{dr list item|wg=lwg|dr=227|std=C++98|before={{tt|T}} was not required to be {{named req|CopyConstructible}} or {{named req|DefaultConstructible}}<br>(a temporary object of type {{tt|T}} might not be able to be constructed)|after={{tt|T}} is also required to<br>be {{named req|CopyConstructible}}}} | ||
+ | {{dr list item|wg=lwg|dr=809|std=C++98|before=arrays could not be swapped|after=added overload {{v|2}}}} | ||
+ | {{dr list item|wg=lwg|dr=2554|std=C++11|before=swapping multi-dimensional arrays can never<br>be {{c/core|noexcept}} due to name lookup problems|after=made to work}} | ||
+ | {{dr list end}} | ||
===See also=== | ===See also=== | ||
− | {{ | + | {{dsc begin}} |
− | {{ | + | {{dsc inc|cpp/utility/ranges/dsc swap}} |
− | {{ | + | {{dsc inc|cpp/algorithm/dsc iter_swap}} |
− | {{ | + | {{dsc inc|cpp/algorithm/dsc swap_ranges}} |
− | {{ | + | {{dsc inc|cpp/utility/dsc exchange}} |
+ | {{dsc end}} | ||
+ | |||
+ | {{langlinks|de|es|fr|it|ja|pt|ru|zh}} |
Latest revision as of 19:32, 1 September 2024
Defined in header <algorithm>
|
(until C++11) |
|
Defined in header <utility>
|
(since C++11) |
|
Defined in header <string_view>
|
||
template< class T > void swap( T& a, T& b ); |
(1) | (conditionally noexcept since C++11) (constexpr since C++20) |
template< class T2, std::size_t N > void swap( T2 (&a)[N], T2 (&b)[N] ); |
(2) | (conditionally noexcept since C++11) (constexpr since C++20) |
Exchanges the given values.
This overload participates in overload resolution only if std::is_move_constructible_v<T> && std::is_move_assignable_v<T> is true. |
(since C++17) |
This overload participates in overload resolution only if std::is_swappable_v<T2> is true. |
(since C++17) |
Contents |
[edit] Parameters
a, b | - | the values to be swapped |
Type requirements | ||
-T must meet the requirements of CopyConstructible and CopyAssignable(until C++11)MoveConstructible and MoveAssignable(since C++11).
| ||
-T2 must meet the requirements of Swappable.
|
[edit] Return value
(none)
[edit] Exceptions
(none) |
(until C++11) |
noexcept specification:
noexcept( std::is_nothrow_move_constructible<T>::value && |
(since C++11) |
noexcept specification:
The lookup for the identifier noexcept(noexcept(swap(*a, *b))) swap in the exception specification finds this function template in addition to anything found by the usual lookup rules, making the exception specification equivalent to C++17 std::is_nothrow_swappable.
|
(since C++11) (until C++17) |
noexcept specification:
noexcept(std::is_nothrow_swappable_v<T2>) |
(since C++17) |
[edit] Complexity
[edit] Specializations
|
(until C++20) |
The expected way to make a program-defined type swappable is to provide a non-member function swap in the same namespace as the type: see Swappable for details.
The following overloads are already provided by the standard library:
(C++11) |
specializes the std::swap algorithm (function template) |
(C++11) |
specializes the std::swap algorithm (function template) |
(C++11) |
specializes the std::swap algorithm (function template) |
(C++11) |
specializes the std::swap algorithm (function template) |
(C++11) |
specializes the std::swap algorithm (function template) |
(C++11) |
specializes the std::swap algorithm (function template) |
specializes the std::swap algorithm (function template) | |
(C++11) |
specializes the std::swap algorithm (function template) |
specializes the std::swap algorithm (function template) | |
(C++11) |
specializes the std::swap algorithm (function template) |
specializes the std::swap algorithm (function template) | |
specializes the std::swap algorithm (function template) | |
specializes the std::swap algorithm (function template) | |
specializes the std::swap algorithm (function template) | |
specializes the std::swap algorithm (function template) | |
specializes the std::swap algorithm (function template) | |
specializes the std::swap algorithm (function template) | |
specializes the std::swap algorithm (function template) | |
specializes the std::swap algorithm (function template) | |
specializes the std::swap algorithm (function template) | |
(C++11) |
specializes the std::swap algorithm (function template) |
specializes the std::swap algorithm (function template) | |
(C++11) |
specializes the std::swap algorithm (function template) |
(C++11) |
specializes the std::swap algorithm (function template) |
specializes the std::swap algorithm (function template) | |
specializes the std::swap algorithm (function template) | |
specializes the std::swap algorithm (function template) | |
specializes the std::swap algorithm (function template) | |
specializes the std::swap algorithm (function template) | |
specializes the std::swap algorithm (function template) | |
specializes the std::swap algorithm (function template) | |
specializes the std::swap algorithm (function template) | |
specializes the std::swap algorithm (function template) | |
specializes the std::swap algorithm (function template) | |
specializes the std::swap algorithm (function template) | |
specializes the std::swap algorithm (function template) | |
specializes the std::swap algorithm (function template) | |
(C++11) |
specializes the std::swap algorithm (function template) |
specializes the std::swap algorithm (function template) | |
(C++11) |
specializes the std::swap algorithm (function) |
(C++11) |
specializes the std::swap algorithm (function template) |
(C++14) |
specializes the std::swap algorithm (function template) |
(C++11) |
specializes the std::swap algorithm (function template) |
specializes the std::swap algorithm (function template) | |
(C++17) |
specializes the std::swap algorithm (function template) |
(C++17) |
specializes the std::swap algorithm (function) |
(C++17) |
specializes the std::swap algorithm (function template) |
specializes the std::swap algorithm (function template) | |
(C++17) |
specializes the std::swap algorithm (function) |
(C++23) |
specializes the std::swap algorithm (function) |
(C++20) |
specializes the std::swap algorithm (function) |
specializes the std::swap algorithm (function) | |
(C++20) |
specializes the std::swap algorithm (function) |
(C++20) |
specializes the std::swap algorithm (function) |
[edit] Example
#include <algorithm> #include <iostream> namespace Ns { class A { int id {}; friend void swap(A& lhs, A& rhs) { std::cout << "swap(" << lhs << ", " << rhs << ")\n"; std::swap(lhs.id, rhs.id); } friend std::ostream& operator<<(std::ostream& os, A const& a) { return os << "A::id=" << a.id; } public: A(int i) : id {i} {} A(A const&) = delete; A& operator = (A const&) = delete; }; } int main() { int a = 5, b = 3; std::cout << a << ' ' << b << '\n'; std::swap(a, b); std::cout << a << ' ' << b << '\n'; Ns::A p {6}, q {9}; std::cout << p << ' ' << q << '\n'; // std::swap(p, q); // error, type requirements are not satisfied swap(p, q); // OK, ADL finds the appropriate friend `swap` std::cout << p << ' ' << q << '\n'; }
Output:
5 3 3 5 A::id=6 A::id=9 swap(A::id=6, A::id=9) A::id=9 A::id=6
[edit] Defect reports
The following behavior-changing defect reports were applied retroactively to previously published C++ standards.
DR | Applied to | Behavior as published | Correct behavior |
---|---|---|---|
LWG 227 | C++98 | T was not required to be CopyConstructible or DefaultConstructible(a temporary object of type T might not be able to be constructed)
|
T is also required tobe CopyConstructible |
LWG 809 | C++98 | arrays could not be swapped | added overload (2) |
LWG 2554 | C++11 | swapping multi-dimensional arrays can never be noexcept due to name lookup problems |
made to work |
[edit] See also
(C++20) |
swaps the values of two objects (customization point object) |
swaps the elements pointed to by two iterators (function template) | |
swaps two ranges of elements (function template) | |
(C++14) |
replaces the argument with a new value and returns its previous value (function template) |