イテレータ
コンテナのスマートなポインタ.
基本的なイテレータ
イテレータはコンテナ内の要素を指すスマートなポインタです。
#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() で移植可能なコード