C++ 標準ライブラリ<iterator>
C++ 標準ライブラリの<iterator>ヘッダファイルは、コンテナ内の要素を走査するための一連のツールを提供します。イテレータは C++ 標準テンプレートライブラリ(STL)の中核的概念の一つであり、プログラマがコンテナの具体的な実装詳細を気にすることなく、統一的な方法でコンテナ内の要素にアクセスすることを可能にします。
イテレータは、コンテナ内の要素を走査する方法を提供するオブジェクトです。イテレータはコンテナ内の要素を指すポインタと見なすことができますが、ポインタよりも柔軟で強力です。イテレータはコンテナ内の要素にアクセスしたり変更したりするために使用でき、STL アルゴリズムと一緒に使用することもできます。
イテレータは主に以下の種類に分類されます:
- 入力イテレータ(Input Iterator):読み取り操作を1回だけ行うことができ、書き込み操作はできません。
- 出力イテレータ(Output Iterator):書き込み操作を1回だけ行うことができ、読み取り操作はできません。
- 前方イテレータ(Forward Iterator):読み取りと書き込みの操作が可能で、前方に移動できます。
- 双方向イテレータ(Bidirectional Iterator):前方イテレータのすべての操作に加えて、後方にも移動できます。
- ランダムアクセスイテレータ(Random Access Iterator):双方向イテレータのすべての操作に加えて、例えば添え字による要素へのアクセスといったランダムアクセスも可能です。
よく使う関数(重要)
| 関数 | 機能 | 例 | 説明 |
|---|---|---|---|
std::advance(it, n) |
イテレータを n 歩移動させる | advance(it, 2); |
元のイテレータを変更する |
std::distance(a, b) |
2つのイテレータ間の距離を計算する | distance(v.begin(), v.end()); |
要素数を返す |
std::next(it, n) |
前方に n 歩進んだ新しいイテレータを返す | auto it2 = next(it, 2); |
推奨、元の値を変更しない |
std::prev(it, n) |
後方に n 歩進んだ新しいイテレータを返す | auto it2 = prev(it, 1); |
C++11 からサポート |
イテレータアダプタ(非常に重要)
イテレータアダプタはイテレータの動作を変更し、さまざまな使用シーンに適応させることができます。
| アダプタ | 機能 | 例 |
|---|---|---|
std::back_inserter |
末尾への挿入(push_back を呼び出す) | back_inserter(vec) |
std::front_inserter |
先頭への挿入(push_front を呼び出す) | front_inserter(list) |
std::inserter |
指定位置への挿入 | inserter(vec, it) |
ストリームイテレータ(IO簡略化の神器)
| 型 | 機能 | 例 |
|---|---|---|
std::istream_iterator |
入力ストリームからデータを読み取る | istream_iterator<int>(cin) |
std::ostream_iterator |
出力ストリームに書き込む | ostream_iterator<int>(cout, " ") |
イテレータの構文
イテレータの構文は通常次のようになります:
#include <iterator>
// 使用迭代器遍历容器
for (ContainerType::iterator it = container.begin(); it != container.end(); ++it) {
// 访问元素 *it
}
例
以下は、<iterator>ヘッダファイルとイテレータによる走査std::vectorの例です:
例
#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>
int main() {
// vector コンテナを作成して初期化する
std::vector<int> vec = {1, 2, 3, 4, 5};
// イテレータを使用して vector を走査する
for (std::vector<int>::iterator it = vec.begin(); it != vec.end(); ++it) {
std::cout << *it << " ";
}
std::cout << std::endl;
// auto キーワードを使用してイテレータの型を簡略化する
for (auto it = vec.begin(); it != vec.end(); ++it) {
std::cout << *it << " ";
}
std::cout << std::endl;
// C++11 の範囲 for ループを使用する
for (int elem : vec) {
std::cout << elem << " ";
}
std::cout << std::endl;
// back_inserter を使用して自動的に挿入する
std::vector<int> v2;
std::fill_n(std::back_inserter(v2), 3, 100);
// ostream_iterator を使用して出力する
std::copy(v2.begin(), v2.end(),
std::ostream_iterator<int>(std::cout, " "));
std::cout << std::endl;
return 0;
}
#include <vector>
#include <iterator>
#include <algorithm>
int main() {
// vector コンテナを作成して初期化する
std::vector<int> vec = {1, 2, 3, 4, 5};
// イテレータを使用して vector を走査する
for (std::vector<int>::iterator it = vec.begin(); it != vec.end(); ++it) {
std::cout << *it << " ";
}
std::cout << std::endl;
// auto キーワードを使用してイテレータの型を簡略化する
for (auto it = vec.begin(); it != vec.end(); ++it) {
std::cout << *it << " ";
}
std::cout << std::endl;
// C++11 の範囲 for ループを使用する
for (int elem : vec) {
std::cout << elem << " ";
}
std::cout << std::endl;
// back_inserter を使用して自動的に挿入する
std::vector<int> v2;
std::fill_n(std::back_inserter(v2), 3, 100);
// ostream_iterator を使用して出力する
std::copy(v2.begin(), v2.end(),
std::ostream_iterator<int>(std::cout, " "));
std::cout << std::endl;
return 0;
}
出力結果:
1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 100 100 100
まとめ
<iterator>の中核的な役割は次の3点にまとめられます:
- 統一されたアクセス方法:異なるコンテナでも同じ走査ロジックを使用する
- コンテナとアルゴリズムの分離:アルゴリズムはイテレータのみに依存する
- コードの再利用性の向上:同じコードを複数のデータ構造に適用できる
初心者は、以下の内容を優先して習得することをお勧めします:
next / prev / distanceback_inserter- イテレータの走査方法