<T>::iterator QList::end()

2025-06-06

イテレータとは?

イテレータは、コンテナ内の要素を順番にアクセスするためのオブジェクトです。C++の標準ライブラリ(STL)におけるイテレータと同様の概念です。ポインタのように振る舞い、*演算子で指している要素の値を取得したり、++演算子で次の要素に進んだりすることができます。

QList::end()の役割

QList<T>::end()が返すイテレータは、**リストの最後の要素の「次」**を指します。これは重要なポイントです。通常の要素を指すわけではなく、リストの範囲外の「仮想的な位置」を指していると考えられます。

この「最後の要素の次」を指すイテレータは、主にループの終了条件として使用されます。例えば、リストのすべての要素を処理する典型的なループは以下のようになります。

QList<QString> myList;
myList << "Apple" << "Banana" << "Cherry";

// QList<QString>::iterator は Qt::Iterator を継承しています
// QList<QString>::iterator i; の代わりに auto i; と書くこともできます
for (QList<QString>::iterator i = myList.begin(); i != myList.end(); ++i) {
    qDebug() << *i; // イテレータが指す要素の値を出力
}

このコードでは、myList.begin()がリストの最初の要素を指すイテレータを返し、ループはimyList.end()に達するまで続きます。i != myList.end()という条件は、「現在のイテレータがリストの終端に達していない限り」という意味になります。

なぜ「最後の要素の次」なのか?

この「番兵(sentinel)イテレータ」の概念は、以下のような利点があります。

  1. ループの終了条件の統一: begin()からend()までという統一された方法で、コンテナの全要素を処理できます。end()が実際の要素を指さないため、ループ内で「最後の要素だけ特別扱いする」といったロジックが不要になります。
  2. 範囲の表現: [begin(), end())という半開区間(beginは含むがendは含まない)で、コンテナの要素の範囲を表現できます。これはSTLの多くのアルゴリズムでも採用されている一般的な慣習です。

<T>はテンプレート引数で、QListが格納する要素の型を示します。例えば、QList<int>であればint型、QList<QString>であればQString型になります。



  1. end()イテレータのデリファレンス(Dereferencing the end() iterator):

    • エラー: end()が返すイテレータは、リストの最後の要素の「次」の仮想的な位置を指します。そのため、このイテレータをデリファレンス(*end_iteratorのようにアクセス)しようとすると、未定義の動作(Undefined Behavior, UB)となり、セグメンテーションフォールト(Segmentation Fault)やクラッシュを引き起こす可能性が高いです。
    • :
      QList<int> myList;
      // ... リストに要素を追加 ...
      if (!myList.isEmpty()) {
          // これは安全だが、意図しない使い方になりやすい
          // QList::last()やQList::back()を使うべき
          int lastValue = *(--myList.end()); // これは最後の要素を指すが、空のリストではUB
      }
      // 以下は絶対にやってはいけない
      // int value = *myList.end(); // クラッシュの原因
      
    • トラブルシューティング: end()イテレータは、ループの終了条件としてのみ使用し、その値を直接参照してはいけません。リストの最後の要素にアクセスしたい場合は、QList::last()またはQList::back()を使用してください。ただし、これらの関数はリストが空でないことを保証する必要があります(QList::isEmpty()でチェック)。
  2. ループ条件の誤り(Incorrect Loop Condition):

    • エラー: forループやwhileループでイテレータを使用する際、終了条件を誤ると、要素がスキップされたり、リストの終端を超えてアクセスしようとしたりする可能性があります。
    • :
      QList<int> myList = {1, 2, 3};
      // 間違い: `i <= myList.end()` はイテレータには適用できない
      // または、最後の要素が処理されない、あるいは終端を超えてアクセスされる可能性
      for (QList<int>::iterator i = myList.begin(); i <= myList.end(); ++i) { // 間違い
          // ...
      }
      
    • トラブルシューティング: イテレータのループでは、常にi != myList.end()の形式を使用します。
  3. イテレータの無効化(Iterator Invalidation):

    • エラー: QListは暗黙的な共有(Implicit Sharing)を使用しており、要素の追加、削除、またはコンテナのコピーといった非const操作を行うと、既存のイテレータが無効になることがあります。無効になったイテレータを使用しようとすると、未定義の動作やクラッシュが発生します。
    • 特に問題となるケース:
      • ループ内でQList::insert()QList::removeAt()QList::erase()QList::append()QList::prepend()などの非constメソッドを呼び出す場合。
      • QListがコピーされ、元のQListのイテレータを使い続ける場合。
    • :
      QList<int> myList = {1, 2, 3, 4, 5};
      for (QList<int>::iterator i = myList.begin(); i != myList.end(); ++i) {
          if (*i % 2 == 0) {
              myList.removeOne(*i); // イテレータ i は無効になる可能性がある
                                   // 特にQt 5以前では危険
          }
      }
      
    • トラブルシューティング:
      • 要素を削除する場合: QList::erase()メソッドは、削除後の次の有効なイテレータを返します。これを利用してループを継続します。
        QList<int> myList = {1, 2, 3, 4, 5};
        QList<int>::iterator i = myList.begin();
        while (i != myList.end()) {
            if (*i % 2 == 0) {
                i = myList.erase(i); // eraseは次の有効なイテレータを返す
            } else {
                ++i;
            }
        }
        
      • for (const T &value : container) (範囲ベースforループ): Qt 5以降では、範囲ベースforループが非常に便利で、イテレータの無効化の問題を回避しやすくなります(ただし、ループ中にコンテナを変更すると同様に問題が発生します)。読み取り専用のイテレーションに最適です。
      • インデックスベースのループ: for (int i = 0; i < myList.size(); ++i) のようなインデックスベースのループは、イテレータの無効化の影響を受けにくいですが、要素の挿入や削除でインデックスがずれる可能性に注意が必要です。要素を削除する場合は、ループの方向を逆にする(for (int i = myList.size() - 1; i >= 0; --i))のが一般的です。
  4. const_iteratoriteratorの混同:

    • エラー: constQListに対して非constbegin()/end()を呼び出そうとしたり、非constQListに対してconst_iteratorを使用する際にconstBegin()/constEnd()ではなくbegin()/end()(非const版)を呼び出してしまい、意図しないdetachを引き起こしたりする。
    • トラブルシューティング:
      • 読み取り専用でリストを走査する場合は、常にconst_iteratorを使用し、QList::constBegin()QList::constEnd()を呼び出します。これにより、暗黙的な共有されたコンテナが不必要にdetachされるのを防ぎ、パフォーマンスを向上させることができます。
      • リストの要素を変更する必要がある場合は、iteratorを使用し、QList::begin()QList::end()を呼び出します。
  5. 空のリストに対するイテレータ操作:

    • エラー: 空のリストに対してbegin()end()は同じイテレータを返します。この状態で--myList.end()のようにして最後の要素にアクセスしようとすると、やはり未定義の動作となります。
    • トラブルシューティング: QList::isEmpty()を呼び出して、リストが空でないことを確認してから、要素へのアクセスやイテレータの操作を行います。
  6. 一時的なend()イテレータの生成(Temporary end() Iterator Generation):

    • 最適化の問題: 大規模なQListをループする際に、ループ条件内で毎回myList.end()を呼び出すと、イテレータオブジェクトが毎回作成・破棄され、わずかなオーバーヘッドが生じる可能性があります。
    • :
      // 毎回 end() が呼ばれる
      for (QList<SomeClass>::const_iterator itr = container.constBegin(); itr != container.constEnd(); ++itr) {
          // ...
      }
      
    • トラブルシューティング: ループに入る前にend()イテレータを一度だけ取得し、それをループ条件で使用することで、このオーバーヘッドを回避できます。
      QList<SomeClass> container;
      // ... 要素を追加 ...
      
      QList<SomeClass>::ConstIterator endIt = container.constEnd(); // endイテレータをキャッシュ
      for (QList<SomeClass>::ConstIterator itr = container.constBegin(); itr != endIt; ++itr) {
          // ...
      }
      
      これは大規模なコンテナでのパフォーマンス最適化であり、通常の使用では大きな問題にはなりません。


QList<T>::iterator QList::end() のプログラミング例

QList::end()は、主にQListの要素をイテレータを使って走査する際に、ループの終了条件として使用されます。

基本的なループでの使用例

最も基本的なQListの走査方法です。

#include <QCoreApplication>
#include <QList>
#include <QDebug> // qDebug() を使うために必要

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    QList<QString> fruits;
    fruits.append("Apple");
    fruits.append("Banana");
    fruits.append("Cherry");
    fruits.append("Date");

    qDebug() << "--- QList::end() を使った基本的なループ ---";

    // QList<QString>::iterator は、QList<QString>::begin() と QList<QString>::end() が返す型
    // auto キーワードを使うと型推論してくれるので便利
    for (QList<QString>::iterator it = fruits.begin(); it != fruits.end(); ++it) {
        // *it はイテレータが指す要素の値を返す
        qDebug() << "Fruit: " << *it;
    }

    qDebug() << "--- const_iterator を使った読み取り専用ループ ---";
    // 要素を変更しない場合は、const_iterator を使うのがベストプラクティス
    // QList::constBegin() と QList::constEnd() を使用
    for (QList<QString>::const_iterator cit = fruits.constBegin(); cit != fruits.constEnd(); ++cit) {
        qDebug() << "Const Fruit: " << *cit;
        // *cit = "Orange"; // const_iterator なのでコンパイルエラーになる
    }

    return a.exec();
}

解説

  • *it: イテレータが現在指している要素の値をデリファレンス(参照)します。
  • ++it: イテレータを次の要素に進めます。
  • it != fruits.end(): ループの終了条件です。イテレータitfruits.end()と等しくない限り、ループは続行されます。
  • fruits.end(): リストの最後の要素の「次」を指すイテレータを返します。
  • fruits.begin(): リストの最初の要素を指すイテレータを返します。

要素の検索とイテレータの利用

特定の要素を検索し、その位置を示すイテレータを取得する例です。

#include <QCoreApplication>
#include <QList>
#include <QDebug>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    QList<int> numbers;
    numbers << 10 << 20 << 30 << 40 << 50;

    int search_value = 30;
    QList<int>::iterator found_it = numbers.begin();
    bool found = false;

    // begin() から end() まで走査して値を探す
    for (; found_it != numbers.end(); ++found_it) {
        if (*found_it == search_value) {
            found = true;
            break; // 見つかったらループを抜ける
        }
    }

    if (found) {
        qDebug() << search_value << "is found.";
        // found_it は現在、検索した要素を指している
        qDebug() << "Value at found position: " << *found_it;
    } else {
        qDebug() << search_value << "is not found.";
        // この場合、found_it は numbers.end() になっているはず
        if (found_it == numbers.end()) {
            qDebug() << "Iterator reached end().";
        }
    }

    // Qtの便利な検索関数 QList::contains() や QList::indexOf() もある
    if (numbers.contains(40)) {
        qDebug() << "40 is in the list.";
    }

    return a.exec();
}

解説

  • もし要素が見つかれば、breakでループを抜け、found_itは検索した要素を指したままになります。
  • found_itnumbers.end()に到達したとき、それは目的の要素が見つからなかったことを意味します。

ループ内での要素の削除 (イテレータの無効化に注意)

これが最も一般的な間違いが発生しやすいシナリオです。QList::erase()を使って安全に削除します。

#include <QCoreApplication>
#include <QList>
#include <QDebug>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    QList<int> values;
    values << 1 << 2 << 3 << 4 << 5 << 6 << 7 << 8 << 9 << 10;

    qDebug() << "Original list:" << values;

    // 偶数だけをリストから削除する
    qDebug() << "--- 偶数を削除(安全な方法)---";
    QList<int>::iterator it = values.begin();
    while (it != values.end()) { // end() を毎回評価するが、イテレータが無効化されない限り安全
        if (*it % 2 == 0) {
            // erase() は、削除された要素の次の有効なイテレータを返す
            it = values.erase(it);
        } else {
            // 要素を削除しなかった場合は、手動で次の要素に進める
            ++it;
        }
    }

    qDebug() << "List after removing even numbers:" << values; // 期待される出力: (1, 3, 5, 7, 9)

    // 別の例: 特定の値を削除
    QList<QString> names;
    names << "Alice" << "Bob" << "Charlie" << "Bob" << "David";
    qDebug() << "Original names:" << names;

    QList<QString>::iterator name_it = names.begin();
    while (name_it != names.end()) {
        if (*name_it == "Bob") {
            name_it = names.erase(name_it); // "Bob"を削除
        } else {
            ++name_it;
        }
    }
    qDebug() << "Names after removing 'Bob':" << names; // 期待される出力: ("Alice", "Charlie", "David")


    return a.exec();
}

解説

  • whileループとif/elseの組み合わせで、要素を削除した場合と削除しない場合でイテレータの進め方を制御するのが重要です。
  • 安全な方法
    QList::erase(iterator)を使用します。このメソッドは、削除された要素の次の有効なイテレータを返すため、ループの継続にその戻り値を使用できます。
  • 誤った方法 (避けるべき)
    ループ内でQList::removeOne()QList::removeAt()などを呼び出して、そのイテレータをそのまま使い続けると、イテレータが無効化されてクラッシュする可能性があります。

QList::last() または QList::back() を使った最後の要素へのアクセス

end()イテレータをデリファレンスして最後の要素にアクセスするのは誤りです。代わりに専用のメソッドを使用します。

#include <QCoreApplication>
#include <QList>
#include <QDebug>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    QList<double> temperatures;
    temperatures << 25.5 << 26.0 << 24.8 << 27.1;

    if (!temperatures.isEmpty()) {
        // QList::last() と QList::back() は同じ機能を持つ
        // 最後の要素を返す
        double lastTemp = temperatures.last();
        qDebug() << "Last temperature (using last()):" << lastTemp;

        double backTemp = temperatures.back();
        qDebug() << "Last temperature (using back()):" << backTemp;

        // QList::last() や QList::back() を呼び出す前に、
        // リストが空でないことを確認することが重要です。
        // 空のリストで呼び出すと未定義の動作になります。
    } else {
        qDebug() << "Temperature list is empty.";
    }

    // 誤った例 (クラッシュや未定義動作の原因)
    // if (!temperatures.isEmpty()) {
    //     double invalidAccess = *temperatures.end(); // 絶対にやらないでください!
    // }

    return a.exec();
}

解説

  • これらのメソッドを呼び出す前に、QList::isEmpty()でリストが空でないことを確認することが非常に重要です。空のリストでこれらのメソッドを呼び出すとプログラムがクラッシュする可能性があります。
  • QList::last()QList::back()は、リストの最後の要素への参照を返します。

QList::iterator を使った基本的なループ

最も一般的な使用例は、リストのすべての要素を順番に処理するループです。

#include <QCoreApplication>
#include <QList>
#include <QDebug> // qCout の代わりに qDebug() を使用するのがQtでは一般的です

int main(int argc, char *argv[]) {
    QCoreApplication a(argc, argv);

    QList<QString> fruits;
    fruits << "Apple" << "Banana" << "Cherry" << "Date";

    // QList<QString>::iterator を使ったループ
    // begin() は最初の要素を指すイテレータを返す
    // end() は最後の要素の「次」を指すイテレータを返す
    qDebug() << "--- Iterating with QList::iterator ---";
    for (QList<QString>::iterator it = fruits.begin(); it != fruits.end(); ++it) {
        // イテレータが指す要素の値にアクセスするには * 演算子を使用
        qDebug() << "Fruit:" << *it;
    }

    // 要素を直接変更することも可能
    qDebug() << "\n--- Modifying elements with QList::iterator ---";
    QList<int> numbers;
    numbers << 10 << 20 << 30 << 40;

    for (QList<int>::iterator it = numbers.begin(); it != numbers.end(); ++it) {
        *it += 5; // 各要素に5を加算
        qDebug() << "Modified Number:" << *it;
    }
    // numbers は [15, 25, 35, 45] になっている

    return a.exec();
}

解説

  • *it: イテレータが指す要素の値にアクセスします。QList::iterator は非 const なイテレータなので、*it = value; のように要素の値を変更することもできます。
  • for (QList<QString>::iterator it = fruits.begin(); it != fruits.end(); ++it):
    • fruits.begin(): リストの最初の要素を指すイテレータを取得し、it に初期化します。
    • it != fruits.end(): ループの継続条件です。現在のイテレータ it がリストの終端イテレータ (fruits.end()) と等しくない限り、ループは続きます。つまり、すべての要素が処理されるまで繰り返されます。
    • ++it: イテレータを次の要素に進めます。

QList::const_iterator を使った読み取り専用ループ

要素の値を変更する必要がない場合は、const_iterator を使用するのが良いプラクティスです。これは、意図しない変更を防ぎ、QListの内部的な最適化(暗黙的な共有)を最大限に活用できます。

#include <QCoreApplication>
#include <QList>
#include <QDebug>

int main(int argc, char *argv[]) {
    QCoreApplication a(argc, argv);

    const QList<double> prices = {1.99, 2.49, 0.99, 5.00}; // const QList

    qDebug() << "--- Iterating with QList::const_iterator (const list) ---";
    for (QList<double>::const_iterator it = prices.constBegin(); it != prices.constEnd(); ++it) {
        qDebug() << "Price:" << *it;
        // *it = 10.0; // コンパイルエラー: const_iterator なので要素の変更はできない
    }

    QList<int> scores = {85, 92, 78}; // 非 const QListでも const_iterator は使える
    qDebug() << "\n--- Iterating with QList::const_iterator (non-const list) ---";
    for (QList<int>::const_iterator it = scores.constBegin(); it != scores.constEnd(); ++it) {
        qDebug() << "Score:" << *it;
    }

    return a.exec();
}

解説

  • prices.constBegin() / prices.constEnd(): 非 constQList でも、明示的にconst_iterator を取得したい場合にこれらのメソッドを使用します。これにより、リストが内部的に detach されるのを防ぎ、パフォーマンスを向上させることができます。
  • const QList<double> prices: リスト自体を const にすると、begin()end() は自動的に const_iterator を返します。

C++11 以降の範囲ベース for ループ (推奨)

Qt 5 以降、C++11 の機能が利用可能であれば、範囲ベース for ループ(Range-based for loop)が最も簡潔で推奨されるイテレーション方法です。内部的にはイテレータを使用していますが、その詳細を意識する必要がありません。

#include <QCoreApplication>
#include <QList>
#include <QDebug>

int main(int argc, char *argv[]) {
    QCoreApplication a(argc, argv);

    QList<QString> items = {"Item A", "Item B", "Item C"};

    qDebug() << "--- Iterating with C++11 range-based for loop (read-only) ---";
    for (const QString &item : items) { // 読み取り専用アクセス
        qDebug() << "Item:" << item;
    }

    qDebug() << "\n--- Iterating with C++11 range-based for loop (modifiable) ---";
    QList<int> values = {1, 2, 3};
    for (int &value : values) { // 要素を変更する場合(参照で受け取る)
        value *= 10;
        qDebug() << "Value:" << value;
    }
    // values は [10, 20, 30] になっている

    return a.exec();
}

解説

  • for (int &value : values): values リストの各要素を int& 型の value として取り出します。これにより、ループ内で要素の値を変更できます。
  • for (const QString &item : items): items リストの各要素を const QString& 型の item として取り出し、ループを実行します。要素のコピーを防ぎ、読み取り専用でアクセスします。

ループ中にリストから要素を削除する場合、イテレータの無効化に注意が必要です。QList::erase() は削除後の次の有効なイテレータを返すため、これを利用して安全にループを継続できます。

#include <QCoreApplication>
#include <QList>
#include <QDebug>

int main(int argc, char *argv[]) {
    QCoreApplication a(argc, argv);

    QList<int> numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

    qDebug() << "Original list:" << numbers;

    // 偶数をリストから削除する
    qDebug() << "\n--- Removing even numbers ---";
    QList<int>::iterator it = numbers.begin();
    while (it != numbers.end()) { // end() を使ったループ条件
        if (*it % 2 == 0) {
            it = numbers.erase(it); // 要素を削除し、次の有効なイテレータを取得
        } else {
            ++it; // 削除しなかった場合は次の要素へ進む
        }
    }

    qDebug() << "List after removing even numbers:" << numbers; // 出力: 1, 3, 5, 7, 9

    return a.exec();
}
  • else { ++it; }: 要素を削除しなかった場合は、通常通りイテレータをインクリメントして次の要素に進みます。
  • it = numbers.erase(it);: erase()は要素を削除し、削除された要素のの要素を指すイテレータを返します。これにより、ループを安全に続行できます。


インデックスベースのアクセス(operator[] または at())

QListはインデックスによる高速なアクセスをサポートしています。これは、C++の配列のように要素にアクセスする直感的な方法です。end()イテレータの概念は必要ありません。

特徴

  • 要素の追加/削除によるインデックスのずれ: ループ中に要素を追加または削除すると、既存のインデックスがずれる可能性があるため、注意が必要です。
  • 境界チェック: operator[]は境界チェックを行いません。無効なインデックスにアクセスすると未定義の動作になります。at()は境界チェックを行い、範囲外アクセスの場合にクラッシュしますが、operator[]よりもわずかに遅くなる可能性があります。
  • 要素の変更: 非constQListの場合、operator[] を使って要素の値を変更できます。
  • 高速なアクセス: QListは内部的に配列として実装されているため、インデックスによるアクセスは非常に高速(定数時間)です。

使用例

#include <QCoreApplication>
#include <QList>
#include <QDebug>

int main(int argc, char *argv[]) {
    QCoreApplication a(argc, argv);

    QList<QString> colors;
    colors << "Red" << "Green" << "Blue" << "Yellow";

    qDebug() << "--- Accessing elements by index ---";
    for (int i = 0; i < colors.size(); ++i) {
        // operator[] でアクセス (書き換え可能)
        // qDebug() << "Color (via []):" << colors[i];

        // at() でアクセス (読み取り専用、境界チェックあり)
        qDebug() << "Color (via at()):" << colors.at(i);
    }

    // 要素の変更
    if (!colors.isEmpty()) {
        colors[0] = "Crimson"; // 最初の要素をCrimsonに変更
    }
    qDebug() << "Modified list:" << colors;

    return a.exec();
}

Qtのforeachキーワード(非推奨だが古いコードで見られる)

Qt 4の時代に導入された、Qt独自の foreach キーワード(マクロ)があります。これはC++11の範囲ベースforループに似ていますが、いくつかの重要な違いがあります。

特徴

  • 非推奨: C++11の範囲ベースforループが登場したため、現在では非推奨とされており、新しいコードでは使用すべきではありません。QtのドキュメントでもC++11の範囲ベースforループへの移行が推奨されています。
  • コンテナのコピー: foreachはループに入る際に常にコンテナのコピーを作成します(ただし、Qtの暗黙的な共有により、変更がない限りは高速です)。このため、ループ内で要素を変更しても、元のコンテナには反映されません。
  • 簡潔な構文: イテレータを明示的に扱う必要がなく、コードが簡潔になります。

使用例

#include <QCoreApplication>
#include <QList>
#include <QDebug>

int main(int argc, char *argv[]) {
    QCoreApplication a(argc, argv);

    QList<int> scores;
    scores << 75 << 88 << 92 << 60;

    qDebug() << "--- Iterating with Qt's foreach keyword ---";
    foreach (int score, scores) { // 'int score' は要素のコピーを受け取る
        qDebug() << "Score:" << score;
        // score += 10; // ここで変更しても、元の scores リストには影響しない
    }
    qDebug() << "Scores after foreach (not modified):" << scores; // 75, 88, 92, 60 のまま

    return a.exec();
}

Javaスタイルのイテレータ (QListIterator, QMutableListIterator)

QtはJavaに似たスタイルのイテレータも提供しています。これらはSTLスタイルのイテレータよりも高レベルで、hasNext(), next(), toBack() などのメソッドを持ちます。

特徴

  • イテレータの無効化に対する挙動: QListIteratorを使用中にリストが変更された場合、イテレータは元のリストのコピー上で動作を継続し、新しい変更を無視します。これは、STLスタイルのイテレータが無効化されるのとは異なる挙動です。
  • 読み取り専用と書き込み可能: QListIteratorは読み取り専用、QMutableListIteratorは要素の変更や削除が可能です。
  • Java風の使いやすさ: Javaプログラマーには馴染みやすいAPIです。

使用例

#include <QCoreApplication>
#include <QList>
#include <QDebug>
#include <QListIterator>      // 読み取り専用
#include <QMutableListIterator> // 読み書き可能

int main(int argc, char *argv[]) {
    QCoreApplication a(argc, argv);

    QList<QString> names;
    names << "Alice" << "Bob" << "Charlie";

    qDebug() << "--- Iterating with QListIterator ---";
    QListIterator<QString> i(names);
    while (i.hasNext()) {
        qDebug() << "Name:" << i.next();
    }

    qDebug() << "\n--- Iterating and Modifying with QMutableListIterator ---";
    QList<int> data = {1, 2, 3, 4, 5};
    QMutableListIterator<int> j(data);
    while (j.hasNext()) {
        int value = j.next();
        if (value % 2 == 0) {
            j.remove(); // 偶数を削除
        } else {
            j.setValue(value * 10); // 奇数は10倍
        }
    }
    qDebug() << "Modified data:" << data; // 出力: 10, 30, 50

    return a.exec();
}
  • j.setValue(newValue): QMutableListIteratorの場合、現在イテレータが指している要素の値を変更できます。
  • j.remove(): QMutableListIteratorの場合、現在イテレータが指している要素をリストから削除できます。
  • i.next(): 次の要素に進み、その要素の値を返します。
  • i.hasNext(): 次の要素が存在するかどうかを確認します。STLの it != list.end() に相当する役割です。
  • QListIterator<QString> i(names);: QListIteratorのコンストラクタにリストを渡します。イテレータはリストの先頭に位置します。
  • Qtのforeachキーワード は、古いコードベースに存在する可能性はありますが、新規コードではC++11の範囲ベースforループを使用すべきです。
  • Javaスタイルのイテレータ (QListIterator, QMutableListIterator) は、特定のユースケース(例: 前後への移動、要素の削除と更新を柔軟に行う)や、Java風のイテレーションに慣れている場合に有用です。
  • STLスタイルのイテレータ (begin(), end()) は、QList::erase() のようにイテレータを直接操作する必要がある場合や、STLアルゴリズム(std::sort, std::findなど)と組み合わせて使用する場合に不可欠です。
  • インデックスベースのループ (for (int i = 0; i < list.size(); ++i)) は、特定のインデックスが必要な場合や、ループ中に要素を削除する際にインデックスがずれる問題に注意しながら使用できます(例: 逆順にループする)。
  • 最も推奨されるのはC++11以降の範囲ベース for ループ (for (const T &value : container)) です。ほとんどの読み取り専用のイテレーションで最も簡潔で、エラーを起こしにくいです。要素を変更したい場合は for (T &value : container) を使用します。