かんたんイテレータ

くるくるまわーる


イテレータ (iterator、反復子) は、コンテナの要素にアクセスするための、コンテナクラス付属のクラス

コンテナクラスに対して、その要素を見る窓のようなクラスだよ。

このインスタンスに演算子を使うことで、

  • 要素の参照を取得する (* 単項演算子)
  • 次の要素に移動する (++ / + 演算子)
  • 前の要素に移動する (-- / - 演算子)

などなどといったことができる。

とりあえず、実際にコンテナクラスのイテレータに触れていこう。

std::vector::iterator

std::vector のイテレータクラスは std::vector::iterator

最初の要素のイテレータは begin、末尾の更に後ろの存在しない要素は end で取得できる。

std::vector<int> data = {1, 4, 5, 2};

std::vector<int>::iterator head = data.begin();

*head; // 1
++head;
*head; // 4
*head = 3;

std::vector<int>::iterator tail = data.end();

*tail; // これは末尾の次の要素なので不定
--tail;
*tail; // 2
--tail;
--tail;
*tail; // 3

いくつかのメンバ関数は、引数にイテレータを取る。

std::vector<int> data = {4, 2, 2, 3};

// insert は イテレータ の位置以降を後ろにずらして、そこに 値 を入れる
data.insert(data.begin() + 1, 5); // 1 番目に 5 を挿入

data; // {4, 5, 2, 2, 3}

// erase は イテレータ の指す要素を削除して、それ以降を前に詰める
data.erase(data.begin() + 2); // 2 番目を削除

data; // {4, 5, 2, 3}

// erase は イテレータの範囲 (以上, 未満) を削除するものもある
data.erase(data.begin() + 2, data.begin() + 4); // 2 番目以上 4 番目未満を削除

data; // {4, 5}

std::map::iterator

std::map のイテレータクラスは std::map::iterator

最初の要素のイテレータは begin、末尾の更に後ろの存在しない要素は end で取得できる。

イテレータでアクセスする要素の順番は、昇順 (小さい数から大きい数、文字列とかは辞書順) になっている。

なお、イテレータでアクセスした要素は、キーと値がセットになった std::pair クラスになっている。

このクラスからは、first / second メンバ変数でそれぞれ キー / を取得できる。

std::map<int, int> data = {
  {1, 4},
  {5, 2}
};

std::map<int, int>::iterator head = data.begin();

*head; // {1, 4}
++head;
*head; // {5, 2}
(*head).second = 3;

std::map<int, int>::iterator tail = data.end();

*tail; // これは末尾の次の要素なので不定
--tail;
*tail; // {5, 3}
--tail;
(*tail).first; // 1

イテレータを引数に取ったり、戻り値として返したりするメンバ関数はあるけれど、特に有用というわけでもないので紹介しないよ。

イテレータと範囲 for

さて、久しぶりの 範囲 for だよ。

実は、範囲 for 文はイテレータがあるものなら何でも使えるよ。

std::vector<int> data = {1, 5, 2, 3, 4};
for (int element : data) {
  std::cout << element << "\n";
}
std::cout << "値を何個入れるの? : ";
int input_n = 0;
std::cin >> input_n;

// input_n 個の入力を受付る
std::vector<double> input(input_n);
for (int &element : input) {
  std::cin >> element;
}
std::map<std::string, int> score = {
  {"Ange", 510},
  {"Lize", 480},
  {"Toko", 540}
};

std::cout << "--- Score ---\n";
for (std::pair<std::string, int> element : score) {
  std::cout << element.first << ": "
    << element.second << " Pt.\n";
}

イテレータの大事さがわかったかな?

ちなみに、配列にイテレータがあるわけじゃないけど、特別に同じように扱えるようになっているよ。