函数模板
C++98: <algorithm>, C++11: <utility>
std::swap
// defined in <algorithm> before C++11template <class T> void swap (T& a, T& b);
非数组 (1) | template <class T> void swap (T& a, T& b) noexcept (is_nothrow_move_constructible<T>::value && is_nothrow_move_assignable<T>::value); |
---|
数组 (2) | template <class T, size_t N> void swap(T (&a)[N], T (&b)[N]) noexcept (noexcept(swap(*a,*b))); |
---|
交换两个对象的数值
交换 a 和 b 的值。
在 C++11 之前,此函数定义在头文件
<algorithm>
中。
此函数模板的行为等同于
1 2 3 4
|
template <class T> void swap ( T& a, T& b )
{
T c(a); a=b; b=c;
}
|
请注意,此函数涉及拷贝构造和两次赋值操作,对于存储大量数据的类,这可能不是交换其内容的最有效方法,因为每次操作的时间复杂度都与其大小成线性关系。
大型数据类型可以提供此函数的重载版本来优化其性能。特别是,所有
标准容器 都会对其进行特化,只交换少量内部指针而不是其全部内容,从而使其操作时间复杂度为常数。
这些函数模板的行为等同于
1 2 3 4 5 6 7 8
|
template <class T> void swap (T& a, T& b)
{
T c(std::move(a)); a=std::move(b); b=std::move(c);
}
template <class T, size_t N> void swap (T &a[N], T &b[N])
{
for (size_t i = 0; i<N; ++i) swap (a[i],b[i]);
}
|
标准库(在 std 命名空间内)的许多组件都会以 *非限定* 方式调用 swap,以便可以调用非基本类型的自定义重载版本,而不是此通用版本:在与要为其提供的类型相同的命名空间中声明的 swap 自定义重载版本,通过 *依赖于参数的查找* 选择,而不是此通用版本。
参数
- a, b
- 两个对象,它们的数值被交换。
类型 T 必须是 *可拷贝构造* 且 *可赋值*。
类型
T 必须是 *可移动构造* 且 *可移动赋值*(或为其定义了
swap,对应版本 *(2)*)。
示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
|
// swap algorithm example (C++11)
#include <iostream> // std::cout
#include <utility> // std::swap
int main () {
int x=10, y=20; // x:10 y:20
std::swap(x,y); // x:20 y:10
int foo[4]; // foo: ? ? ? ?
int bar[] = {10,20,30,40}; // foo: ? ? ? ? bar: 10 20 30 40
std::swap(foo,bar); // foo: 10 20 30 40 bar: ? ? ? ?
std::cout << "foo contains:";
for (int i: foo) std::cout << ' ' << i;
std::cout << '\n';
return 0;
}
|
输出
foo contains: 10 20 30 40
|
复杂度
非数组: 常数:执行一次构造和两次赋值(尽管请注意,每次操作都根据其自身复杂度进行)。
数组: 线性于 N:对每个元素执行一次交换操作。
异常
如果类型 T 的构造或赋值操作抛出异常,则此函数抛出异常。
如果 T 是 *无异常移动构造* 且 *无异常移动赋值*,则永远不会抛出异常。
请注意,如果 T 不满足上述要求(在 parameters 中指定),将导致 *未定义行为*。