最終更新日時: 2025年07月14日 23時04分00秒 (JST)
Koichi Murase が更新

履歴 編集

function template
<utility>

# std::swap(C++11)

    namespace std {
      template <class T>
      void swap(T& a, T& b);                               // (1) C++03 in <algorithm> header

      template <class T>
      void swap(T& a, T& b) noexcept(see below);           // (1) C++11

      template <class T>
      constexpr void swap(T& a, T& b) noexcept(see below); // (1) C++20

      template <class T, size_t N>
      void swap(T (&a)[N], T (&b)[N])
                         noexcept(noexcept(swap(*a, *b))); // (2) C++11

      template <class T, size_t N>
      constexpr void swap(T (&a)[N], T (&b)[N])
                         noexcept(noexcept(swap(*a, *b))); // (2) C++20
    }

## 概要

2つの値を入れ替える。

## 要件

- 値版：型`T`は`MoveConstructible`かつ`MoveAssignable`でなければならない。
- 配列版：範囲`[0, N)`内の全ての`i`において、`a[i]`と`b[i]`は`Swappable`でなければならない。

## 効果

値版の振る舞いは、以下のコードと等価である：

    template <class T>
    void swap(T& a, T& b) {
      T t = std::move(a);
      a = std::move(b);
      b = std::move(t);
    }

配列版の振る舞いは、以下のコードと等価である：

    template <class T, size_t N>
    void swap(T (&a)[N], T (&b)[N]) {
      for (std::size_t i = 0; i < N; ++i) {
        swap(a[i], b[i]);
      }
    }

つまり、範囲`[0, N)`内の全ての`i`について、 `swap(a[i], b[i]);` を呼び出す。

この関数の内部における`swap()`呼び出しは、 `std::swap(a[i], b[i]);` という形ではなく、 `swap(a[i], b[i]);`という形で行われる。すなわち、`T`型に対してオーバーロードされた`swap()`関数がある場合には、常にそちらが呼ばれる。

そのため、`swap()`関数を呼び出す場合は、直接`std::swap(a, b);`と呼び出すのではなく、

    using std::swap;
    swap(a, b);

のように呼び出し、各クラスに対し個別に定義された swap がある場合には そちらが呼ばれるようにするべきである。

## 戻り値

なし

## 例外

- 値版：`noexcept`中の式は、以下と等価である：`is_nothrow_move_constructible<T>::value && is_nothrow_move_assignable<T>::value`
- 配列版：配列の要素型`T`に対する`swap()`操作が例外を投げない場合、この関数もまた例外を投げない

## 備考

C++03では`<algorithm>`ヘッダに定義されていた。

## 例

    #include <iostream>
    #include <utility>

    template <class Array>
    void print(const Array& ar)
    {
      std::cout << '[';
      bool first = true;
      for (auto x : ar) {
        if (first) {
          first = false;
        }
        else {
          std::cout << ',';
        }
        std::cout << x;
      }
      std::cout << ']';
    }

    int main()
    {
      // 値版
      {
        int a = 1;
        int b = 2;

        using std::swap;
        swap(a, b);

        std::cout << a << ", " << b << std::endl;
      }

      // 配列版
      {
        int a[] = {1, 2, 3};
        int b[] = {4, 5, 6};

        using std::swap;
        swap(a, b);

        print(a);
        std::cout << ", ";
        print(b);
        std::cout << std::endl;
      }
    }

### 出力

    2, 1
    [4,5,6], [1,2,3]

## バージョン

### 言語

- C++11

### 処理系

- Clang: ??
- GCC: 4.7.0 ✅
- ICC: ??
- Visual C++: 2012 ✅, 2013 ✅, 2015 ✅
  - 値版はそれより前から実装されている。

## 関連項目

- `std::ranges::swap()`
- `std::iter_swap()`

## 参照

- LWG Issue 809. `std::swap` should be overloaded for array types
  - C++11で、配列に対するオーバーロードが追加された経緯のレポート
- P0879R0 Constexpr for `swap` and `swap` related functions