function template
C++98: <algorithm>, C++11: <utility>

std::swap

template <class T> void swap (T& a, T& b);
头文件
// moved from <algorithm> to <utility> in C++11
非数组 (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)));
交换两个对象的数值
交换 ab 的值。

此函数模板的行为等同于
1
2
3
4
template <class T> void swap ( T& a, T& b )
{
  T c(a); a=b; b=c;
}

请注意,此函数涉及复制构造和两次赋值操作,对于存储大量数据的类的交换内容而言,这可能不是最高效的方式,因为这些操作中的每一个通常都与其大小成线性关系。

大型数据类型可以提供此函数的重载版本来优化其性能。特别是,所有标准容器都对其进行了专门化处理,只交换少数内部指针,而不是其全部内容,使其操作时间为常数。
此函数不再定义在头文件<algorithm>中,而是在<utility>中。

这些函数模板的行为等同于
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 的自定义重载,通过*依赖于参数的查找*(argument-dependent lookup)而非此通用版本来选择。

参数

a, b
两个对象,它们的 contents 被交换。
类型 T 必须是*可复制构造*(copy-constructible)且*可赋值*(assignable)的。
类型 T 必须是*可移动构造*(move-constructible)且*可移动赋值*(move-assignable)的(对于版本 (2),或者为其定义了 swap)。

返回值



示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// swap algorithm example (C++98)
#include <iostream>     // std::cout
#include <algorithm>    // std::swap
#include <vector>       // std::vector

int main () {

  int x=10, y=20;                              // x:10 y:20
  std::swap(x,y);                              // x:20 y:10

  std::vector<int> foo (4,x), bar (6,y);       // foo:4x20 bar:6x10
  std::swap(foo,bar);                          // foo:6x10 bar:4x20

  std::cout << "foo contains:";
  for (std::vector<int>::iterator it=foo.begin(); it!=foo.end(); ++it)
    std::cout << ' ' << *it;
  std::cout << '\n';

  return 0;
}

输出
foo contains: 10 10 10 10 10 10


复杂度

非数组:常数:执行一次构造和两次赋值(尽管请注意,这些操作中的每一个都基于其自身复杂度)。
数组:相对于 N 为线性:对每个元素执行一次交换操作。

数据竞争

ab 都被修改。

异常

如果类型 T 的构造或赋值操作抛出异常,则此函数也抛出异常。
如果 T 是*无抛出移动构造*(nothrow-move-constructible)且*无抛出移动赋值*(nothrow-move-assignable)的,则此函数永不抛出异常。
请注意,如果 T 不满足上面(在 parameters 中)指定的要求,则会导致*未定义行为*(undefined behavior)。

另见