イテレータ

コンテナのスマートなポインタ.

基本的なイテレータ

イテレータはコンテナ内の要素を指すスマートなポインタです。

#include <iostream>
#include <vector>

int main() {
    std::vector<int> v = {1, 2, 3, 4, 5};
    
    // イテレータで走査
    for (auto it = v.begin(); it != v.end(); ++it) {
        std::cout << *it << " ";  // *it で値にアクセス
    }
    std::cout << std::endl;
    
    // イテレータで要素を変更
    *(v.begin() + 2) = 99;  // インデックス2の要素を99に
    
    for (auto x : v) std::cout << x << " ";
    std::cout << std::endl;
    
    return 0;
}

1 2 3 4 5
1 2 99 4 5

const_iterator(読み取り専用)

const_iterator を使用すると、要素の変更ができません。

#include <iostream>
#include <vector>

int main() {
    std::vector<int> v = {1, 2, 3, 4, 5};
    
    // const_iterator で読み取りのみ
    for (auto it = v.cbegin(); it != v.cend(); ++it) {
        std::cout << *it << " ";
        // *it = 10;  // エラー:読み取り専用
    }
    std::cout << std::endl;
    
    return 0;
}

1 2 3 4 5

逆順イテレータ

rbegin() / rend() で逆向きに走査できます。

#include <iostream>
#include <vector>

int main() {
    std::vector<int> v = {1, 2, 3, 4, 5};
    
    std::cout << "順向き: ";
    for (auto it = v.begin(); it != v.end(); ++it) {
        std::cout << *it << " ";
    }
    std::cout << std::endl;
    
    std::cout << "逆向き: ";
    for (auto it = v.rbegin(); it != v.rend(); ++it) {
        std::cout << *it << " ";
    }
    std::cout << std::endl;
    
    return 0;
}

順向き: 1 2 3 4 5
逆向き: 5 4 3 2 1

イテレータ種別

コンテナの種類によって、サポートされるイテレータ操作が異なります。

  • Input Iterator:読み込みのみ、前進のみ(例:入力ストリーム)
  • Output Iterator:出力のみ、前進のみ(例:std::back_inserter)
  • Forward Iterator:読み書き、前進のみ
  • Bidirectional Iterator:読み書き、前後移動可能(例:list, set)
  • Random Access Iterator:O(1)で任意位置アクセス(例:vector, deque)
#include <iostream>
#include <vector>
#include <list>
#include <algorithm>

int main() {
    // vector: Random Access イテレータ
    std::vector<int> v = {1, 2, 3, 4, 5};
    auto v_it = v.begin() + 2;  // OK: + で位置移動
    std::cout << "vector[2]: " << *v_it << std::endl;
    
    // list: Bidirectional イテレータ
    std::list<int> l = {1, 2, 3, 4, 5};
    auto l_it = l.begin();
    ++l_it;   // OK: ++ でインクリメント
    ++l_it;   // もう一度
    // l_it = l.begin() + 2;  // ERROR: list は + をサポートしません
    std::cout << "list position: ";
    std::advance(l_it, 1);  // std::advance で2ステップ移動
    std::cout << *l_it << std::endl;
    
    return 0;
}

vector[2]: 3
list position: 4

イテレータの演算

Random Access イテレータのみが算術演算をサポート。

#include <iostream>
#include <vector>

int main() {
    std::vector<int> v = {10, 20, 30, 40, 50};
    
    auto it = v.begin();
    
    // イテレータの演算
    std::cout << "*it: " << *it << std::endl;
    std::cout << "*(it + 2): " << *(it + 2) << std::endl;
    std::cout << "*(it + 4): " << *(it + 4) << std::endl;
    std::cout << "距離 (v.end() - v.begin()): " 
              << (v.end() - v.begin()) << std::endl;
    
    return 0;
}

*it: 10
*(it + 2): 30
*(it + 4): 50
距離 (v.end() - v.begin()): 5

std::advance と std::distance

すべてのイテレータで使える移動・距離計算関数。

#include <iostream>
#include <list>
#include <vector>
#include <algorithm>

int main() {
    std::list<int> l = {1, 2, 3, 4, 5};
    
    auto it = l.begin();
    std::advance(it, 3);  // 3つ前進
    std::cout << "3つ前進後: " << *it << std::endl;
    
    // 距離計算
    int dist = std::distance(l.begin(), it);
    std::cout << "距離: " << dist << std::endl;
    
    return 0;
}

3つ前進後: 4
距離: 3

よくある誤り

  • 誤り: list に it + 2 を使用 → 改善: Random Access ではない、std::advance() を使用
  • 誤り: end() のイテレータに * でアクセス → 改善: end() は有効な要素を指さない
  • 誤り: イテレータ無効化後も使用 → 改善: erase() 後は新しいイテレータが必要
  • 誤り: コンテナ変更後の古いイテレータ使用 → 改善: 再取得する必要がある場合がある

ポイント

  • イテレータはコンテナの要素へのスマートなアクセス方法
  • begin()/end(), cbegin()/cend(), rbegin()/rend() の組み合わせ
  • Random Access イテレータのみ []+ 演算をサポート
  • list や set ではイテレータ無効化に注意
  • std::advance() と std::distance() で移植可能なコード