初心者向けQt QList解説:const_iteratorと安全なイテレーション

2025-06-06

それぞれの要素を分解して見ていきましょう。

  1. QList<T>:

    • これはQtの提供するテンプレートクラスで、動的な配列(リスト)を表現します。C++のstd::vectorstd::listに似ています。
    • <T>はテンプレートパラメータであり、QListが格納する要素の型を表します。例えば、QList<QString>であれば文字列のリスト、QList<int>であれば整数のリストを意味します。
  2. const_iterator:

    • これはQListの内部で定義されている型で、リストの要素を順に辿っていくための「イテレータ」の一種です。
    • const」が付いていることから分かるように、このイテレータを使ってリストの要素の値を変更することはできません。要素を読み取る(アクセスする)ことのみが可能です。
    • C++標準ライブラリ(STL)のstd::vector::const_iteratorなどと同様の振る舞いをします。*iteratorで要素の値を取得でき、++iteratorで次の要素へ進むことができます。
  3. QList::constBegin():

    • これはQListクラスのメンバー関数です。
    • この関数を呼び出すと、リストの「最初の要素」を指すconst_iteratorが返されます。
    • このイテレータは、リストの要素を先頭から順に走査(イテレート)する際に、ループの開始点としてよく使用されます。

QList<T>::const_iterator QList::constBegin() は、

QList<T>型のリストにおいて、そのリストの先頭要素を指す、要素の値を変更できない読み取り専用のイテレータを返します」

という意味になります。

使用例

#include <QList>
#include <QString>
#include <QDebug> // デバッグ出力用

int main() {
    QList<QString> myList;
    myList.append("Apple");
    myList.append("Banana");
    myList.append("Cherry");

    // constBegin() を使ってリストの要素を読み取り専用で走査
    QList<QString>::const_iterator it = myList.constBegin();
    while (it != myList.constEnd()) { // constEnd() はリストの末尾の「次」を指すイテレータを返す
        qDebug() << *it; // イテレータが指す要素の値を取得
        ++it;            // 次の要素へ進む
    }

    // C++11以降の範囲ベースforループを使うと、より簡潔に記述できます
    qDebug() << "--- Range-based for loop ---";
    for (const QString& item : myList) {
        qDebug() << item;
    }

    return 0;
}


よくあるエラーとトラブルシューティング

const_iterator を通した要素変更の試み

これは最も頻繁に発生するエラーです。const_iteratorは要素を読み取るためだけのものであり、値を変更することはできません。

  • トラブルシューティング
    リストの要素を変更したい場合は、QList::iterator を返す QList::begin() を使用してください。
    QList<int> myList = {1, 2, 3};
    QList<int>::iterator it = myList.begin(); // const がないことに注意
    *it = 10; // OK
    qDebug() << myList; // 結果: (10, 2, 3)
    
  • 発生するエラーメッセージ例
    error: assignment of read-only location ‘* it’ (「読み取り専用の場所 *it への代入」)
  • エラーの状況
    QList<int> myList = {1, 2, 3};
    QList<int>::const_iterator it = myList.constBegin();
    *it = 10; // エラー!
    

無効なイテレータの参照外し (Dereferencing an invalid iterator)

イテレータが無効な位置を指しているときに、そのイテレータの参照外し (*it) を行おうとすると、クラッシュや未定義動作につながります。

  • トラブルシューティング
    • イテレータを使用する際は、必ずループ条件 it != list.constEnd() で有効性をチェックしてください。
    • 空のリストの場合、constBegin()constEnd() と等しくなります。標準的なループ構文を使っていれば、空のリストに対してはループ本体が実行されないため、安全に処理できます。
    QList<int> myList; // 空のリスト
    // 正しいループ構造
    for (QList<int>::const_iterator it = myList.constBegin(); it != myList.constEnd(); ++it) {
        // このブロックは空のリストでは実行されないので安全
        qDebug() << *it;
    }
    
    myList.append(100); // 要素を追加
    for (QList<int>::const_iterator it = myList.constBegin(); it != myList.constEnd(); ++it) {
        qDebug() << *it; // OK
    }
    
  • 発生するエラーメッセージ/症状
    コンパイルエラーではなく、実行時エラー(セグメンテーション違反、アクセス違反)が発生し、プログラムがクラッシュすることが多いです。
  • エラーの状況例
    • QListが空なのに、ループに入る前に*myList.constBegin()のように直接参照外しをする。
    • myList.constEnd() はリストの最後の要素の「次」を指すため、これを参照外しする。
    QList<int> emptyList;
    // 間違い: 空のリストの先頭イテレータを参照外ししようとする(チェックなし)
    // int value = *emptyList.constBegin(); // クラッシュまたは未定義動作のリスク
    
    QList<int> myList = {1, 2, 3};
    // 間違い: constEnd() を参照外ししようとする
    // int value = *myList.constEnd(); // クラッシュまたは未定義動作
    

イテレーション中のコンテナ変更によるイテレータの無効化 (Iterator invalidation)

QListのイテレータは、イテレーション中にリストの要素が追加されたり削除されたりすると、無効になる可能性があります。無効なイテレータを使用すると、予期せぬ結果やクラッシュにつながります。

  • トラブルシューティング
    • イテレーション中にリストを変更しない
      これが最も安全な方法です。
    • 変更が必要な場合
      • 変更対象の要素を別のリストに収集し、ループ後に処理する。
      • インデックスベースのループを使用する
        QListoperator[]をサポートしているので、インデックスを使って安全に走査・変更できます。ただし、要素の削除を行うとインデックスがずれるため注意が必要です。
      • C++11以降の範囲ベースforループを使う
        これもイテレーション中の変更には弱いですが、読み取り専用のループとしては安全で簡潔です。
      • std::remove_ifのようなアルゴリズムを検討する。
      • 要素の削除を行う場合は、逆方向からイテレートする
        constRBegin()/constREnd() や、QList::removeAt()などを使いつつインデックスを調整する方法があります。
  • 発生するエラーメッセージ/症状
    実行時エラー(クラッシュ)、無限ループ、間違った要素へのアクセス、または予期しないプログラムの振る舞い。コンパイラは通常これを警告しません。
  • エラーの状況例
    QList<QString> names = {"Alice", "Bob", "Charlie"};
    for (QList<QString>::const_iterator it = names.constBegin(); it != names.constEnd(); ++it) {
        if (*it == "Bob") {
            // 間違い: イテレーション中にリストを変更しようとする
            // names.removeOne("Bob"); // これにより it が無効になる可能性がある
            // names.append("David"); // これも無効化のリスク
        }
        qDebug() << *it; // 無効化されたイテレータを参照している可能性
    }
    

空のQListに対する constBegin() の振る舞いの誤解

空のQListに対してconstBegin()を呼び出すと、constEnd()と同じイテレータが返されます。これは正しい動作ですが、誤解していると問題と認識する場合があります。

  • トラブルシューティング
    これはエラーではありません。空のリストの場合、constBegin()constEnd()が等しいという事実が、通常のループ条件 it != list.constEnd() によって適切に処理されます。ループ本体は実行されません。
  • 発生するエラーメッセージ/症状
    特になし。コードは正しく動作します。
  • エラーの状況例
    「リストが空なのにconstBegin()を呼んだら何かエラーになるのでは?」と心配し、不要なチェックを入れる、あるいは、ループが実行されないことをエラーと誤解する。

イテレータの型不一致

const_iteratorを返すconstBegin()の結果を、非constQList::iterator型変数に代入しようとすると、コンパイルエラーになります。

  • トラブルシューティング
    • 変数をQList<T>::const_iterator型として宣言してください。
    • もし要素の変更が必要な場合は、QList::begin()(非constなイテレータを返す)を使用し、その結果をQList<T>::iterator型の変数に代入してください。
  • 発生するエラーメッセージ例
    error: no viable conversion from 'QList<int>::const_iterator' to 'QList<int>::iterator' (「QList<int>::const_iteratorからQList<int>::iteratorへの有効な変換がありません」)
  • エラーの状況例
    QList<int> myList = {1, 2, 3};
    // 間違い: constBegin() の結果を非 const のイテレータに代入しようとする
    // QList<int>::iterator it = myList.constBegin(); // コンパイルエラー
    
  • 最小の再現コードを作成する
    問題が発生した際に、その問題を再現する最小限のコードを切り出すことで、原因の特定が容易になります。
  • Qtドキュメントを参照する
    QList::const_iteratorQList::constBegin() の公式ドキュメントには、その振る舞いや制約に関する詳細が記載されています。
  • デバッガを使用する
    イテレータが無効になったり、予期せぬ値を持つ場合に、デバッガでイテレータの指すアドレスや、コンテナの状態を確認することは非常に有効です。
  • コンパイラのエラーメッセージをよく読む
    C++のコンパイラエラーは時に難解ですが、イテレータ関連のエラーは比較的メッセージが直接的です。エラーメッセージの行番号と内容を注意深く確認しましょう。


基本的な読み取り専用イテレーションの例

最も一般的な使用法です。リストの全要素を先頭から末尾まで読み取ります。

#include <QList>      // QList を使用するために必要
#include <QString>    // QList<QString> の T 型として必要
#include <QDebug>     // デバッグ出力 (qDebug()) を使用するために必要

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

    qDebug() << "リストの要素を const_iterator で走査:";

    // constBegin() でイテレーションを開始し、constEnd() まで繰り返す
    // const_iterator は要素の読み取りのみを許可する
    QList<QString>::const_iterator it = fruits.constBegin();
    while (it != fruits.constEnd()) {
        // *it でイテレータが指す要素の値を取得
        qDebug() << "フルーツ: " << *it;
        // ++it で次の要素へイテレータを進める
        ++it;
    }

    // Qt 6以降では、QList は QStringList のような別名も持ちます
    QList<int> numbers;
    numbers << 10 << 20 << 30 << 40;

    qDebug() << "\n数値リストの要素を const_iterator で走査:";
    for (QList<int>::const_iterator numIt = numbers.constBegin(); numIt != numbers.constEnd(); ++numIt) {
        qDebug() << "数値: " << *numIt;
    }

    return 0;
}

解説

  • ++it;:イテレータを次の要素に進めます。
  • qDebug() << *it;*itはイテレータが現在指している要素の値を返します。const_iteratorなので、この値は変更できません。
  • while (it != fruits.constEnd()):イテレータitがリストの末尾の「次」を指すconstEnd()に到達するまでループを続けます。
  • QList<QString>::const_iterator it = fruits.constBegin();fruitsリストの先頭要素を指すconst_iterator(読み取り専用イテレータ)を取得し、itに代入します。

空のQListに対する振る舞い

空のリストに対してconstBegin()を呼び出すと、それはconstEnd()と同じ値を返します。そのため、上記のような標準的なループ構造であれば、ループ本体は一度も実行されず、安全に処理されます。

#include <QList>
#include <QString>
#include <QDebug>

int main() {
    QList<QString> emptyList;

    qDebug() << "空のリストを const_iterator で走査:";

    QList<QString>::const_iterator it = emptyList.constBegin();
    while (it != emptyList.constEnd()) {
        // この行は、リストが空なので実行されない
        qDebug() << "要素: " << *it;
        ++it;
    }
    qDebug() << "空のリストの走査が完了しました。";

    // 別の例:begin()とend()が同じかどうかの確認
    if (emptyList.constBegin() == emptyList.constEnd()) {
        qDebug() << "空のリストでは constBegin() == constEnd() です。";
    }

    return 0;
}

解説
emptyList.constBegin()emptyList.constEnd()が等しいため、whileループの条件は最初から偽となり、ループ内部のコードは実行されません。これは正しい振る舞いです。

QList::begin()との比較(要素変更の試み)

constBegin()が読み取り専用であることと、begin()が要素の変更を許可することの違いを示します。

#include <QList>
#include <QString>
#include <QDebug>

int main() {
    QList<QString> colors;
    colors << "Red" << "Green" << "Blue";

    qDebug() << "オリジナルのリスト: " << colors;

    // const_iterator を使用した読み取り
    QList<QString>::const_iterator constIt = colors.constBegin();
    // *constIt = "Orange"; // コンパイルエラー: "assignment of read-only location"

    // begin() を使用した書き込み可能なイテレータ
    QList<QString>::iterator modifiableIt = colors.begin();
    if (modifiableIt != colors.end()) {
        *modifiableIt = "Orange"; // OK: 先頭要素を "Orange" に変更
    }
    qDebug() << "変更後のリスト (begin()で変更): " << colors;

    // もし変更したいが const_iterator しか使えない(例えば const な関数内)場合、
    // const_cast を使うのは通常は推奨されない(設計の見直しを推奨)
    // QList<QString>::const_iterator badConstIt = colors.constBegin();
    // QString* ptr = const_cast<QString*>(&*badConstIt);
    // *ptr = "Purple"; // 実行時に問題を起こす可能性がある
    // qDebug() << "const_cast後のリスト: " << colors; // 結果は出るが危険

    return 0;
}

解説

  • 対照的に、QList<QString>::iterator modifiableIt = colors.begin();で取得したmodifiableItは、*modifiableIt = "Orange";のように要素を変更することが可能です。
  • QList<QString>::const_iterator constIt = colors.constBegin();で取得したconstItは、*constIt = "Orange";のように要素を変更しようとするとコンパイルエラーになります。

範囲ベースforループ(モダンC++のイテレーション)

C++11以降で導入された範囲ベースforループは、constBegin()constEnd()を内部で利用することで、イテレーションをより簡潔に記述できます。要素の読み取り専用アクセスに最適です。

#include <QList>
#include <QString>
#include <QDebug>

int main() {
    QList<int> scores;
    scores << 85 << 92 << 78 << 95 << 88;

    qDebug() << "範囲ベースforループでスコアを読み取り:";
    // const int& score: 各要素を読み取り専用の参照として取得
    // これが内部的には const_iterator を使っている
    for (const int& score : scores) {
        qDebug() << "スコア: " << score;
        // score = 100; // コンパイルエラー: const 参照なので変更不可
    }

    QList<QString> cities;
    cities << "Tokyo" << "Osaka" << "Kyoto";

    qDebug() << "\n範囲ベースforループで都市名を読み取り:";
    for (const QString& city : cities) {
        qDebug() << "都市: " << city;
    }

    return 0;
}

解説
for (const int& score : scores) のように記述すると、scoresリストの各要素がscoreに読み取り専用参照として渡されます。これは、内部的にscores.constBegin()scores.constEnd()を使ってイテレーションしているのと同等であり、非常に読みやすいコードになります。

const_iteratorを使っているかどうかにかかわらず、イテレーション中にQListの要素を追加したり削除したりすると、既存のイテレータが無効になり、クラッシュや予期せぬ動作を引き起こす可能性があります。

悪い例(避けるべき)

#include <QList>
#include <QString>
#include <QDebug>

int main() {
    QList<QString> items = {"ItemA", "ItemB", "ItemC", "ItemB"};

    qDebug() << "オリジナルリスト: " << items;

    // 間違い: イテレーション中にリストを変更するとイテレータが無効になる可能性
    // このコードはクラッシュしたり、ItemBがすべて削除されなかったりする可能性があります
    qDebug() << "\n誤ったリスト変更の試み:";
    for (QList<QString>::const_iterator it = items.constBegin(); it != items.constEnd(); ++it) {
        if (*it == "ItemB") {
            // QListの変更はイテレータを無効にする可能性がある!
            // items.removeOne("ItemB"); // 絶対に避けましょう!
            // items.append("NewItem");  // 同様に避けるべき
            qDebug() << "ItemB を見つけましたが、ここで変更すると危険です。";
        } else {
            qDebug() << "処理中: " << *it;
        }
    }
    qDebug() << "変更後のリスト(不確実な状態): " << items; // 結果は不確実

    return 0;
}
  1. イテレーション中に変更しない
    最もシンプルで安全な方法は、イテレーション中はリストの内容を変更しないことです。
  2. 削除対象を別途収集し、後で処理する
    #include <QList>
    #include <QString>
    #include <QDebug>
    
    int main() {
        QList<QString> items = {"ItemA", "ItemB", "ItemC", "ItemB"};
        QList<QString> itemsToRemove; // 削除対象を一時的に保持するリスト
    
        qDebug() << "オリジナルリスト: " << items;
    
        // まずは削除対象の要素を const_iterator で特定・収集する
        for (const QString& item : items) { // 範囲ベースforループで安全に読み取り
            if (item == "ItemB") {
                itemsToRemove.append(item);
            }
        }
    
        // イテレーションが完了した後で、リストの変更を行う
        for (const QString& item : itemsToRemove) {
            items.removeOne(item); // ここで安全に削除
        }
    
        qDebug() << "変更後のリスト(安全な方法): " << items;
    
        return 0;
    }
    
  3. インデックスベースのループを使う
    QListoperator[]をサポートしているので、インデックスでアクセスすることもできます。ただし、途中で削除するとインデックスがずれるため、ループの方向やインデックスの調整に注意が必要です。


範囲ベースforループ (Range-based for loop) - 推奨

C++11以降で導入された範囲ベースforループは、QListのようなコンテナの全要素を読み取る際に、最も簡潔で推奨される方法です。これは内部的にイテレータ(多くの場合const_iterator)を使用しています。

#include <QList>
#include <QString>
#include <QDebug>

int main() {
    QList<QString> products;
    products << "Laptop" << "Mouse" << "Keyboard" << "Monitor";

    qDebug() << "--- 範囲ベースforループで製品名を読み取り ---";
    // const T& item とすることで、要素を読み取り専用の参照として取得します。
    // これが内部的には const_iterator の振る舞いをします。
    for (const QString& item : products) {
        qDebug() << "製品: " << item;
        // item = "New Product"; // コンパイルエラー: const 参照なので変更不可
    }

    // もし要素のコピーで十分なら、const T item でもOK
    qDebug() << "\n--- 範囲ベースforループ (コピー) ---";
    for (const QString item : products) {
        qDebug() << "製品 (コピー): " << item;
    }

    // 要素を変更したい場合は const を外す (ただし、元の QList に const がない場合のみ)
    QList<int> numbers = {1, 2, 3};
    qDebug() << "\n--- 範囲ベースforループ (変更可能) ---";
    for (int& num : numbers) { // 非const参照
        num *= 10; // 要素を変更
    }
    qDebug() << "変更された数値リスト: " << numbers; // 結果: (10, 20, 30)

    return 0;
}

利点

  • 読み取り専用
    const T&を使用することで、要素の意図しない変更を防ぎます。
  • 安全性
    イテレータの管理(begin()/end(), ++it)を明示的に行う必要がないため、ヒューマンエラーが少ない。
  • 簡潔性
    コードが非常に短く、読みやすい。

インデックスベースのアクセス (Index-based Access)

QListはランダムアクセスコンテナであり、インデックスを使って要素に直接アクセスできます。特に、特定のインデックスの要素にアクセスしたい場合や、ループ内でインデックスそのものが必要な場合に便利です。

  • at()
    list.at(index)でアクセスします。範囲外アクセスがあった場合、アサーションエラーやクラッシュ(デバッグビルド)を引き起こし、安全性が高いです。
  • operator[]
    通常の配列アクセスと同じように、list[index]でアクセスします。範囲外アクセスは未定義動作を引き起こします。
#include <QList>
#include <QString>
#include <QDebug>

int main() {
    QList<QString> colors;
    colors << "Red" << "Green" << "Blue" << "Yellow";

    qDebug() << "--- インデックスベースのアクセス ---";
    for (int i = 0; i < colors.size(); ++i) {
        qDebug() << "色 (" << i << "): " << colors[i]; // operator[] を使用
    }

    qDebug() << "\n--- at() を使用したアクセス ---";
    for (int i = 0; i < colors.size(); ++i) {
        qDebug() << "色 (" << i << "): " << colors.at(i); // at() を使用 (Bounds check)
    }

    // 特定のインデックスへの直接アクセス
    if (colors.size() > 2) {
        qDebug() << "\n3番目の色 (インデックス2): " << colors.at(2);
    }

    // インデックスベースでの要素変更 (QList が const でない場合)
    colors[0] = "Crimson"; // 最初の要素を "Crimson" に変更
    qDebug() << "\n変更後の最初の色: " << colors[0];

    return 0;
}

利点

  • 範囲外アクセスに注意が必要(特にoperator[])。
  • ループを記述する際の冗長性。
  • 変更が可能
    constでないQListであれば、インデックスを使って要素を直接変更できます。 欠点:
  • インデックスの利用
    要素の値だけでなく、そのインデックスも必要とする場合に便利です。
  • ランダムアクセス
    任意のインデックスの要素にO(1)でアクセスできます。

foreach マクロ (非推奨 - Deprecated)

Qt 4時代によく使われていたQt独自のイテレーションマクロです。C++11の範囲ベースforループが利用できない古いコンパイラ環境で重宝されましたが、現在は非推奨であり、新しいコードでの使用は避けるべきです。

#include <QList>
#include <QString>
#include <QDebug>

// Qt の foreach マクロを使用 (非推奨)
#include <QtAlgorithms> // 通常は含まれるが明示的に書くことも

int main() {
    QList<int> scores = {100, 95, 80, 75};

    qDebug() << "--- foreach マクロでスコアを読み取り (非推奨) ---";
    // foreach (型 変数名, コンテナ)
    foreach (int score, scores) {
        qDebug() << "スコア: " << score;
    }

    return 0;
}

利点

  • 一般的なC++の構文ではないため、他のC++プロジェクトとの学習コストや互換性の問題があります。
  • コピーオーバーヘッド
    ループ変数に要素のコピーが生成されるため、大きなオブジェクトを扱う場合にパフォーマンスが低下する可能性があります(const T&のような参照アクセスができない)。
  • 非推奨
    新しいC++標準との互換性が低く、Qtの開発ガイドラインでも使用が推奨されていません。
  • C++11より前の環境での簡潔なイテレーション。 欠点

標準C++アルゴリズムとの連携 (<algorithm>)

QListは標準C++のイテレータインターフェース(begin(), end(), constBegin(), constEnd())を提供するため、<algorithm>ヘッダにあるstd::for_each, std::find, std::countなどの豊富なアルゴリズムと組み合わせて使用できます。

#include <QList>
#include <QString>
#include <QDebug>
#include <algorithm> // std::for_each などを使用するために必要

int main() {
    QList<double> temperatures = {25.5, 28.1, 22.3, 30.0, 25.5};

    qDebug() << "--- std::for_each で温度をログ出力 ---";
    // constBegin() と constEnd() を使って範囲を指定し、ラムダ式で各要素を処理
    std::for_each(temperatures.constBegin(), temperatures.constEnd(), [](double temp) {
        qDebug() << "温度: " << temp << "℃";
    });

    qDebug() << "\n--- std::count で特定の温度の数を数える ---";
    int count25_5 = std::count(temperatures.constBegin(), temperatures.constEnd(), 25.5);
    qDebug() << "25.5℃ の回数: " << count25_5;

    // std::find を使って要素を探す
    QList<double>::const_iterator foundIt = std::find(temperatures.constBegin(), temperatures.constEnd(), 22.3);
    if (foundIt != temperatures.constEnd()) {
        qDebug() << "22.3℃ が見つかりました。";
    } else {
        qDebug() << "22.3℃ は見つかりませんでした。";
    }

    return 0;
}

利点

  • アルゴリズムの知識が必要。
  • 単純なイテレーションには冗長になることがある。
  • 効率性
    多くの場合、高度に最適化された実装が提供されます。 欠点:
  • 標準準拠
    標準C++の知識が直接適用でき、他のSTLコンテナとの連携もスムーズです。
  • 強力な機能
    ソート、検索、フィルタリングなど、一般的なコンテナ操作のための豊富なアルゴリズムが提供されます。

QList自体が、特定の要素にアクセスしたり、リストの状態を確認したりするための便利なメンバー関数を多数提供しています。これらは、const_iteratorを使ったループを記述するよりも、直接的で意図が明確になる場合があります。

  • size() / count()
    リストの要素数を返します。
  • isEmpty()
    リストが空かどうかを返します。
  • indexOf(value) / lastIndexOf(value)
    指定された値が最初(または最後)に見つかるインデックスを返します。見つからない場合は-1を返します。
  • count(value)
    指定された値がリストにいくつ含まれているかを返します。
  • contains(value)
    指定された値がリストに含まれているかどうかを返します。
  • value(index, defaultValue)
    指定されたインデックスの要素を返します。インデックスが範囲外の場合、指定されたdefaultValueを返します。
  • first() / last()
    リストの最初の要素、最後の要素を返します。リストが空の場合は未定義動作です。
#include <QList>
#include <QString>
#include <QDebug>

int main() {
    QList<int> data = {10, 20, 30, 20, 40};

    qDebug() << "--- QList メンバー関数 ---";
    if (!data.isEmpty()) {
        qDebug() << "最初の要素: " << data.first();
        qDebug() << "最後の要素: " << data.last();
    }

    qDebug() << "インデックス 2 の要素: " << data.value(2);
    qDebug() << "インデックス 10 (範囲外) の要素 (デフォルト値 999): " << data.value(10, 999);

    qDebug() << "リストに 20 が含まれているか?: " << data.contains(20);
    qDebug() << "リストに 50 が含まれているか?: " << data.contains(50);

    qDebug() << "リスト内の 20 の数: " << data.count(20);

    qDebug() << "最初に 20 が出現するインデックス: " << data.indexOf(20);
    qDebug() << "最後に 20 が出現するインデックス: " << data.lastIndexOf(20);

    return 0;
}
  • 簡潔性
    単純なチェックやアクセスの場合、イテレータを使うよりも記述が短くなります。
  • 目的が明確
    特定の操作を行うための専用関数なので、コードの意図が明確になります。
方法用途推奨度
範囲ベースforループ最も一般的な読み取り専用の全要素走査(モダンC++の推奨)。コードが最も簡潔で安全。◎ 最も推奨。新しいコードではほぼ常にこれを使用すべきです。
インデックスベース特定のインデックスの要素にアクセスしたい場合、またはループ内でインデックスそのものが必要な場合。ランダムアクセス性能が重要。。適切な状況で非常に有効。at()[]よりも範囲チェックがあり安全。
std::for_eachなどQListの要素に対して複雑な操作(変換、フィルタリングなど)を行いたい場合。標準ライブラリの強力なアルゴリズムを活用したい場合。。機能的なプログラミングスタイルを好む場合や、複雑なコンテナ操作を行う場合に有効。
QListメンバー関数first(), last(), contains(), count(), indexOf()など、特定の情報取得や単一要素へのアクセスに限定する場合。。イテレーションなしで目的を達成できる場合に推奨。コードが簡潔になる。
foreachマクロ非推奨。古いQtコードの互換性のため。新しいコードでは使用すべきではありません。。古いコードを読む際に知識として必要だが、新規開発では避けるべき。