C++ 標準ライブラリ<iterator>

C++ 標準ライブラリの<iterator>ヘッダファイルは、コンテナ内の要素を走査するための一連のツールを提供します。イテレータは C++ 標準テンプレートライブラリ(STL)の中核的概念の一つであり、プログラマがコンテナの具体的な実装詳細を気にすることなく、統一的な方法でコンテナ内の要素にアクセスすることを可能にします。

イテレータは、コンテナ内の要素を走査する方法を提供するオブジェクトです。イテレータはコンテナ内の要素を指すポインタと見なすことができますが、ポインタよりも柔軟で強力です。イテレータはコンテナ内の要素にアクセスしたり変更したりするために使用でき、STL アルゴリズムと一緒に使用することもできます。

イテレータは主に以下の種類に分類されます:

  1. 入力イテレータ(Input Iterator):読み取り操作を1回だけ行うことができ、書き込み操作はできません。
  2. 出力イテレータ(Output Iterator):書き込み操作を1回だけ行うことができ、読み取り操作はできません。
  3. 前方イテレータ(Forward Iterator):読み取りと書き込みの操作が可能で、前方に移動できます。
  4. 双方向イテレータ(Bidirectional Iterator):前方イテレータのすべての操作に加えて、後方にも移動できます。
  5. ランダムアクセスイテレータ(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 &lt;iterator&gt;

// 使用迭代器遍历容器
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;
}

出力結果:

1 2 3 4 5 
1 2 3 4 5 
1 2 3 4 5 
100 100 100 

まとめ

<iterator>の中核的な役割は次の3点にまとめられます:

  • 統一されたアクセス方法:異なるコンテナでも同じ走査ロジックを使用する
  • コンテナとアルゴリズムの分離:アルゴリズムはイテレータのみに依存する
  • コードの再利用性の向上:同じコードを複数のデータ構造に適用できる

初心者は、以下の内容を優先して習得することをお勧めします:

  • next / prev / distance
  • back_inserter
  • イテレータの走査方法
その他の拡張