最終更新日時:
が更新

履歴 編集

function template
<utility>

std::swap(C++11)

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

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

概要

2つの値を入れ替える。

要件

  • 値版型TMoveConstructibleかつ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 (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()操作が例外を投げない場合、この関数もまた例外を投げない

#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

処理系

参照