初心者必見!Qt QMapのイテレータ「cend()」プログラミング例と使い方

2025-05-27

QMap::cend()は、このQMapの「終端イテレータ」を返します。具体的には、マップ内の最後の要素の「次」を指すイテレータです。これは、STL(Standard Template Library)のコンテナでよく使われるイテレータの概念と同じです。

詳細

  1. <Key, T>:

    • これはテンプレート引数です。
    • Key はマップのキーの型(例: QString, int など)を表します。QMapはキーで要素をソートして格納するため、Key型は比較演算子<が定義されている必要があります。
    • T はマップの値の型(例: int, MyCustomClass など)を表します。
  2. const_iterator:

    • これはQMapの要素を指すイテレータの型です。
    • constがついてるため、このイテレータを使ってマップの要素(値)を変更することはできません。読み取り専用のアクセスを提供します。
    • もし要素の値を変更したい場合は、QMap::iteratorを使用する必要があります。一般的には、変更の必要がない限りconst_iteratorを使用することが推奨されます。なぜなら、const_iteratorの方がわずかに高速であり、コードの可読性も向上するからです。
  3. QMap::cend():

    • これはQMapクラスのメンバー関数です。
    • この関数は、マップ内の「past-the-end」イテレータ、つまり最後の要素の「1つ後」の位置を指すイテレータを返します。
    • このイテレータ自体は有効な要素を指していないため、このイテレータを逆参照(*イテレータ)することはできません。
    • 主にループの終了条件として使用されます。例えば、マップのすべての要素を反復処理する際に、begin()(またはconstBegin())からcend()(またはend())までループを回すのが一般的なパターンです。

使用例

#include <QMap>
#include <QString>
#include <QDebug>

int main() {
    QMap<QString, int> ages;
    ages.insert("Alice", 30);
    ages.insert("Bob", 25);
    ages.insert("Charlie", 35);

    // QMapのすべての要素をconst_iteratorを使って反復処理する例
    qDebug() << "年齢リスト:";
    QMap<QString, int>::const_iterator i = ages.constBegin(); // あるいは ages.begin()でもOK
    while (i != ages.cend()) { // cend() を使用
        qDebug() << i.key() << ": " << i.value();
        ++i;
    }

    // C++11以降の範囲ベースforループを使う場合 (より簡潔)
    // この場合、内部で cend() が使われます
    qDebug() << "\n年齢リスト (範囲ベースforループ):";
    for (const auto& pair : ages) { // QMapは直接範囲ベースforループに対応
        // pair は QPair<const QString, int> 型
        qDebug() << pair.first << ": " << pair.second;
    }

    return 0;
}


QMap::cend()はマップの終端を指すイテレータであり、主にループの終了条件として使用されます。この性質から、誤った使い方をすると予期せぬ動作やクラッシュを引き起こすことがあります。

cend()が指すイテレータの逆参照 (Dereferencing the past-the-end iterator)

エラーの症状
プログラムがクラッシュする(セグメンテーション違反など)。デバッグ時にイテレータが無効なメモリを指していると表示される。

原因
QMap::cend()が返すイテレータは、マップ内の有効な要素の次の位置を指しており、それ自体は有効な要素を指していません。したがって、cend()が返すイテレータを逆参照(例: *itit.key(), it.value())しようとすると、未定義の動作(通常はクラッシュ)が発生します。

誤ったコード例

QMap<QString, int> myMap;
// ... (マップに要素を追加)

// 最後の要素を処理した後、さらに進もうとしてしまう
QMap<QString, int>::const_iterator it = myMap.constBegin();
if (!myMap.isEmpty()) { // マップが空でない場合でも、最後の要素の次を逆参照する可能性
    it = myMap.cend(); // 意図的にcend()に設定
    qDebug() << "誤った逆参照: " << it.key() << ", " << it.value(); // クラッシュする!
}

正しい使い方とトラブルシューティング
ループの終了条件としてのみcend()を使用し、cend()に到達したイテレータを逆参照しないように注意してください。

QMap<QString, int> myMap;
myMap.insert("A", 1);
myMap.insert("B", 2);

// 正しいループの例
for (QMap<QString, int>::const_iterator it = myMap.constBegin(); it != myMap.cend(); ++it) {
    qDebug() << it.key() << ": " << it.value();
}

// QMap::find() と cend() の組み合わせ
QMap<QString, int>::const_iterator foundIt = myMap.find("C"); // 存在しないキー
if (foundIt == myMap.cend()) {
    qDebug() << "'C' はマップに存在しません。";
} else {
    qDebug() << "Found 'C': " << foundIt.value();
}

無効化されたイテレータの使用 (Using invalidated iterators)

エラーの症状
イテレータを使用しようとするとクラッシュしたり、予期しないデータが返されたりする。

原因
QMapに要素を追加したり削除したりすると、既存のイテレータが無効になる可能性があります。特に、マップの内容が変更されると、イテレータが指す位置やその後の位置が変化するため、以前取得したイテレータが正しく機能しなくなることがあります。

誤ったコード例

QMap<QString, int> myMap;
myMap.insert("Alice", 30);
myMap.insert("Bob", 25);

QMap<QString, int>::const_iterator it = myMap.constBegin(); // イテレータを保持

myMap.insert("Charlie", 35); // マップの内容が変更されると、'it'が無効になる可能性がある

qDebug() << it.key(); // 未定義の動作、クラッシュの可能性

トラブルシューティング
マップの内容を変更する操作(insert(), remove(), clear()など)を行った後は、新しいイテレータを再取得するようにしてください。

QMap<QString, int> myMap;
myMap.insert("Alice", 30);
myMap.insert("Bob", 25);

QMap<QString, int>::const_iterator it = myMap.constBegin();
qDebug() << "初期のイテレータ (Alice): " << it.key();

myMap.insert("Charlie", 35); // マップ変更

// 変更後にイテレータを再取得する
it = myMap.constBegin();
qDebug() << "変更後のイテレータ (再取得): " << it.key();

異なるコンテナのイテレータ同士の比較 (Comparing iterators from different containers)

エラーの症状
コンパイルエラーまたは実行時エラー(未定義の動作)。

原因
C++のコンテナのイテレータは、同じコンテナインスタンスに属するもの同士でのみ比較(==!=)することができます。異なるQMapインスタンスのcend()イテレータ同士を比較しようとすると、意味のない比較となり、エラーやクラッシュにつながります。

誤ったコード例

QMap<QString, int> map1;
map1.insert("A", 1);

QMap<QString, int> map2;
map2.insert("B", 2);

if (map1.cend() == map2.cend()) { // 異なるマップのcend()を比較 - 意味がない
    qDebug() << "これは意味のない比較です。";
}

トラブルシューティング
イテレータは常に、それが取得された元のコンテナインスタンスのイテレータ(begin(), end(), constBegin(), constEnd(), find()など)と比較してください。

QMap::iteratorとQMap::const_iteratorの型不一致 (Type mismatch between iterator and const_iterator)

エラーの症状
コンパイルエラー(例: "cannot convert from 'QMap<Key, T>::const_iterator' to 'QMap<Key, T>::iterator'")。

原因
QMap::cend()は常にconst_iteratorを返します。もしQMap::iterator型の変数にcend()の戻り値を代入しようとすると、型不一致のエラーになります。const_iteratorは読み取り専用であり、iteratorは書き込みも可能であるため、暗黙的な変換は許可されません。

誤ったコード例

QMap<QString, int> myMap;
myMap.insert("Test", 10);

QMap<QString, int>::iterator it = myMap.cend(); // コンパイルエラー!

トラブルシューティング

  • 値を変更したい場合
    QMap::end()を使用するか、QMap::find()で適切なイテレータ(変更可能なイテレータ)を取得し、QMap::end()と比較する。
  • 読み取り専用のループの場合
    const_iteratorを使用する。
QMap<QString, int> myMap;
myMap.insert("Test", 10);

// 読み取り専用の場合 (cend() は常に const_iterator を返す)
QMap<QString, int>::const_iterator constIt = myMap.cend(); // OK

// 値を変更したい場合(end() を使用)
QMap<QString, int>::iterator mutableIt = myMap.find("Test");
if (mutableIt != myMap.end()) { // end() を使用
    mutableIt.value() = 20;
    qDebug() << "変更後: " << mutableIt.value();
}

QMap::const_iteratorで要素を変更しようとする (Attempting to modify elements with const_iterator)

エラーの症状
コンパイルエラー(例: "member 'value' is const" または "assignment of read-only member")。

原因
const_iteratorはその名の通り、指している要素の値を変更することを許可しません。cend()自体がconst_iteratorを返すため、cend()を直接逆参照することはないにしても、const_iteratorでループ中に要素を変更しようとするとこのエラーに直面します。

誤ったコード例

QMap<QString, int> myMap;
myMap.insert("A", 1);
myMap.insert("B", 2);

for (QMap<QString, int>::const_iterator it = myMap.constBegin(); it != myMap.cend(); ++it) {
    // it.value() = 100; // コンパイルエラー! (const_iterator なので変更不可)
}

トラブルシューティング
要素の値を変更する必要がある場合は、const_iteratorではなくQMap::iteratorを使用し、QMap::begin()QMap::end()を使ってループを構築してください。

QMap<QString, int> myMap;
myMap.insert("A", 1);
myMap.insert("B", 2);

for (QMap<QString, int>::iterator it = myMap.begin(); it != myMap.end(); ++it) {
    if (it.key() == "A") {
        it.value() = 100; // OK
    }
}
qDebug() << "Aの値: " << myMap.value("A"); // 出力: 100
  • デバッガの使用
    イテレータ関連のクラッシュや予期せぬ動作が発生した場合、デバッガを使用してイテレータの現在値、指しているコンテナ、およびその有効性を確認することが最も効果的なトラブルシューティング方法です。
  • autoキーワードの利用
    イテレータの型が複雑な場合、autoキーワードを使用すると、コンパイラに適切な型を推論させることができます。これにより、型指定の間違いを防ぎ、可読性を向上させます。
    for (auto it = myMap.constBegin(); it != myMap.cend(); ++it) {
        qDebug() << it.key() << ": " << it.value();
    }
    
  • C++11の範囲ベースforループの活用
    多くのケースで、明示的にbegin()end()cend()を使う代わりに、C++11以降で導入された範囲ベースforループを使用すると、コードが簡潔になり、上記のようなイテレータの誤用を防ぐことができます。
    QMap<QString, int> myMap;
    myMap.insert("A", 1);
    myMap.insert("B", 2);
    
    for (const auto& pair : myMap) { // 読み取り専用の場合
        qDebug() << pair.first << ": " << pair.second;
    }
    
    // 値を変更したい場合 (Qt 5.10以降のkeyValueBegin()/keyValueEnd()を使うか、find()をループで使う)
    // 直接 range-based for で QMap の値を変更するのは少し複雑ですが、
    // QMap::valueRef() (Qt 6) や find() を使って変更イテレータを得るのが一般的です。
    // 簡単な例として、キーで検索して変更する場合:
    QMap<QString, int>::iterator it_a = myMap.find("A");
    if (it_a != myMap.end()) {
        it_a.value() = 1000;
    }
    


QMapの全要素を反復処理する基本的な例

これがcend()の最も一般的な使用例です。マップの先頭から終端まで、読み取り専用で要素を順番に処理します。

#include <QCoreApplication>
#include <QMap>
#include <QString>
#include <QDebug>

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

    QMap<QString, int> studentScores;
    studentScores.insert("Alice", 95);
    studentScores.insert("Bob", 88);
    studentScores.insert("Charlie", 72);
    studentScores.insert("David", 91);

    qDebug() << "--- 学生の成績リスト (QMap::constBegin() と QMap::cend() を使用) ---";
    // QMap::const_iterator を宣言し、constBegin() で初期化
    QMap<QString, int>::const_iterator it = studentScores.constBegin();

    // イテレータが cend() に達するまでループを続ける
    while (it != studentScores.cend()) {
        qDebug() << "名前: " << it.key() << ", 成績: " << it.value();
        ++it; // 次の要素へ進む
    }

    return 0;
}

実行結果例

--- 学生の成績リスト (QMap::constBegin() と QMap::cend() を使用) ---
名前:  "Alice" , 成績:  95
名前:  "Bob" , 成績:  88
名前:  "Charlie" , 成績:  72
名前:  "David" , 成績:  91

特定のキーを検索し、cend()と比較して存在チェックを行う例

QMap::find()は、指定されたキーに対応するイテレータを返します。キーが見つからない場合、cend()(またはend())を返します。この特性を利用して、キーの存在をチェックできます。

#include <QCoreApplication>
#include <QMap>
#include <QString>
#include <QDebug>

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

    QMap<QString, QString> dictionary;
    dictionary.insert("apple", "リンゴ");
    dictionary.insert("banana", "バナナ");
    dictionary.insert("orange", "オレンジ");

    QString searchKey1 = "apple";
    QString searchKey2 = "grape";

    qDebug() << "--- キーの検索と存在チェック ---";

    // 存在するキーの検索
    QMap<QString, QString>::const_iterator foundIt1 = dictionary.find(searchKey1);
    if (foundIt1 != dictionary.cend()) { // cend() と比較
        qDebug() << searchKey1 << " の日本語訳: " << foundIt1.value();
    } else {
        qDebug() << searchKey1 << " は辞書にありません。";
    }

    // 存在しないキーの検索
    QMap<QString, QString>::const_iterator foundIt2 = dictionary.find(searchKey2);
    if (foundIt2 != dictionary.cend()) { // cend() と比較
        qDebug() << searchKey2 << " の日本語訳: " << foundIt2.value();
    } else {
        qDebug() << searchKey2 << " は辞書にありません。";
    }

    return 0;
}

実行結果例

--- キーの検索と存在チェック ---
"apple"  の日本語訳:  "リンゴ"
"grape"  は辞書にありません。

C++11の範囲ベースforループを使用する例(cend()が内部で使われる)

C++11以降では、コンテナの反復処理に範囲ベースforループを使用するのがより簡潔で推奨される方法です。このループは、内部でbegin()/end()(またはconstBegin()/cend())イテレータを使用します。

#include <QCoreApplication>
#include <QMap>
#include <QString>
#include <QDebug>

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

    QMap<int, QString> errorCodes;
    errorCodes.insert(404, "Not Found");
    errorCodes.insert(500, "Internal Server Error");
    errorCodes.insert(200, "OK");

    qDebug() << "--- エラーコードリスト (C++11 範囲ベースforループ) ---";
    // const QMapの場合、自動的に const_iterator が使用される
    // QMap は Key-Value ペアを QPair<const Key, T> として扱います
    for (const auto& entry : errorCodes) {
        qDebug() << "コード: " << entry.first << ", メッセージ: " << entry.second;
    }

    // 非const QMapの場合、デフォルトでは QPair<const Key, T> としてアクセス
    QMap<QString, double> productPrices;
    productPrices.insert("Laptop", 1200.50);
    productPrices.insert("Mouse", 25.99);

    qDebug() << "\n--- 商品価格リスト (C++11 範囲ベースforループ) ---";
    for (const auto& item : productPrices) {
        qDebug() << "商品: " << item.first << ", 価格: " << item.second;
    }

    return 0;
}

実行結果例

--- エラーコードリスト (C++11 範囲ベースforループ) ---
コード:  200 , メッセージ:  "OK"
コード:  404 , メッセージ:  "Not Found"
コード:  500 , メッセージ:  "Internal Server Error"

--- 商品価格リスト (C++11 範囲ベースforループ) ---
商品:  "Laptop" , 価格:  1200.5
商品:  "Mouse" , 価格:  25.99

constEnd()cend()は機能的に同じです。両方ともconst_iteratorを返します。

  • cend(): C++11で導入されたもので、明示的にconst_iteratorを返すことを意図しています。非constQMapオブジェクトに対してもconst_iteratorを取得したい場合に、end()の代わりに推奨されます。
  • constEnd(): QMapオブジェクトがconstである場合に呼び出されるオーバーロード。

多くの場合、どちらを使っても結果は同じですが、cend()を使う方が、より明確に「読み取り専用の終端イテレータが欲しい」という意図を表現できます。

#include <QCoreApplication>
#include <QMap>
#include <QString>
#include <QDebug>

void printMapUsingConstEnd(const QMap<QString, int>& map) {
    qDebug() << "--- printMapUsingConstEnd 関数 (constEnd() を使用) ---";
    for (QMap<QString, int>::const_iterator it = map.constBegin(); it != map.constEnd(); ++it) {
        qDebug() << it.key() << ": " << it.value();
    }
}

void printMapUsingCend(QMap<QString, int>& map) { // 非constなマップでも const_iterator を使う
    qDebug() << "--- printMapUsingCend 関数 (cend() を使用) ---";
    for (QMap<QString, int>::const_iterator it = map.constBegin(); it != map.cend(); ++it) {
        qDebug() << it.key() << ": " << it.value();
    }
}

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

    QMap<QString, int> dataMap;
    dataMap.insert("One", 1);
    dataMap.insert("Two", 2);
    dataMap.insert("Three", 3);

    printMapUsingConstEnd(dataMap); // const参照で渡すので constEnd() が使われる
    printMapUsingCend(dataMap);     // 非constオブジェクトでも cend() が使える

    return 0;
}
--- printMapUsingConstEnd 関数 (constEnd() を使用) ---
"One" :  1
"Three" :  3
"Two" :  2
--- printMapUsingCend 関数 (cend() を使用) ---
"One" :  1
"Three" :  3
"Two" :  2


C++11の範囲ベースforループ (Range-based for loop)

最も現代的で推奨される方法です。コードが簡潔になり、イテレータの管理ミスによるエラーを防ぐことができます。内部的には、QMap::begin()/end()(またはQMap::constBegin()/cend())が使用されます。

#include <QCoreApplication>
#include <QMap>
#include <QString>
#include <QDebug>

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

    QMap<QString, int> scores;
    scores.insert("Alice", 90);
    scores.insert("Bob", 85);
    scores.insert("Charlie", 92);

    qDebug() << "--- C++11 範囲ベースforループ (読み取り専用) ---";
    for (const auto& pair : scores) { // const auto& を使うことで読み取り専用アクセス
        qDebug() << "名前: " << pair.first << ", スコア: " << pair.second;
    }

    qDebug() << "\n--- C++11 範囲ベースforループ (値の変更が必要な場合 - Qt 5.10以降の keyValueBegin()/keyValueEnd() を使用) ---";
    // Qt 5.10 以降では、QMap::keyValueBegin() と QMap::keyValueEnd() を使うと、
    // 範囲ベースforループで値への変更可能な参照を取得できます。
    // それ以前のQtバージョンや、古いC++標準では、この方法は使えません。
    for (auto it = scores.keyValueBegin(); it != scores.keyValueEnd(); ++it) {
        if (it.key() == "Bob") {
            it.value() = 89; // 値の変更
        }
        qDebug() << "名前: " << it.key() << ", スコア: " << it.value();
    }
    // Qt 6.4以降では asKeyValueRange() を使うとさらに簡潔に記述できます (C++17が必要)
    // for (auto [key, value] : scores.asKeyValueRange()) { ... }

    return 0;
}

利点

  • 間違いが起こりにくい。
  • イテレータの初期化や++it!= cend()といった記述が不要。
  • コードが非常に簡潔で読みやすい。

考慮点

  • const auto& を使うと読み取り専用となり、値の変更はできません。値を変更したい場合は、QtのバージョンやC++標準によって異なる方法が必要になります(上記例のkeyValueBegin()/keyValueEnd()など)。
  • C++11以降の標準をサポートするコンパイラが必要。

QtのJavaスタイルイテレータ (QMapIterator, QMutableMapIterator)

Qtは独自のイテレータスタイルも提供しており、Javaのイテレータに似たAPIを持っています。これらはSTLスタイルイテレータより少しオーバーヘッドがありますが、より高レベルな機能を提供します。

  • QMutableMapIterator<Key, T>: 読み書き可能なイテレータで、ループ中に要素を削除することもできます。
  • QMapIterator<Key, T>: 読み取り専用のイテレータ。
#include <QCoreApplication>
#include <QMap>
#include <QString>
#include <QDebug>
#include <QMapIterator>
#include <QMutableMapIterator>

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

    QMap<QString, int> itemQuantities;
    itemQuantities.insert("Pen", 100);
    itemQuantities.insert("Notebook", 50);
    itemQuantities.insert("Eraser", 200);

    qDebug() << "--- Javaスタイルイテレータ (QMapIterator: 読み取り専用) ---";
    QMapIterator<QString, int> i(itemQuantities);
    while (i.hasNext()) {
        i.next(); // 次の要素に進む(これは必須)
        qDebug() << "アイテム: " << i.key() << ", 数量: " << i.value();
    }

    qDebug() << "\n--- Javaスタイルイテレータ (QMutableMapIterator: 読み書きと削除) ---";
    QMutableMapIterator<QString, int> j(itemQuantities);
    while (j.hasNext()) {
        j.next();
        if (j.key() == "Pen") {
            j.value() = 120; // 値の変更
        } else if (j.key() == "Eraser") {
            j.remove(); // 要素の削除
        }
    }

    qDebug() << "\n--- 変更後のマップ内容 ---";
    for (const auto& pair : itemQuantities) {
        qDebug() << "アイテム: " << pair.first << ", 数量: " << pair.second;
    }

    return 0;
}

実行結果例

--- Javaスタイルイテレータ (QMapIterator: 読み取り専用) ---
アイテム:  "Eraser" , 数量:  200
アイテム:  "Notebook" , 数量:  50
アイテム:  "Pen" , 数量:  100

--- Javaスタイルイテレータ (QMutableMapIterator: 読み書きと削除) ---

--- 変更後のマップ内容 ---
アイテム:  "Notebook" , 数量:  50
アイテム:  "Pen" , 数量:  120

利点

  • QMutableMapIteratorはループ中に要素の追加や削除を安全に行える(STLスタイルイテレータではerase()後にイテレータを更新する必要がある)。
  • hasNext()next()といったメソッドにより、イテレータの制御がより明確。

考慮点

  • C++標準ライブラリのイテレータの概念とは少し異なる。
  • STLスタイルイテレータに比べると、パフォーマンスが若干劣る可能性がある。

QMap::keys() と QMap::values() を利用する

マップのキーだけ、または値だけが必要な場合は、これらの関数を使ってリストを取得し、そのリストを反復処理できます。ただし、これはマップ全体をコピーする操作なので、パフォーマンスに注意が必要です。

#include <QCoreApplication>
#include <QMap>
#include <QString>
#include <QDebug>
#include <QList>

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

    QMap<QString, int> productStock;
    productStock.insert("Apple", 100);
    productStock.insert("Banana", 150);
    productStock.insert("Orange", 80);

    qDebug() << "--- QMap::keys() を使用 ---";
    QList<QString> productNames = productStock.keys();
    for (const QString& name : productNames) {
        qDebug() << "商品名: " << name << ", 在庫: " << productStock.value(name);
    }

    qDebug() << "\n--- QMap::values() を使用 ---";
    QList<int> stockCounts = productStock.values();
    for (int count : stockCounts) {
        qDebug() << "在庫数: " << count;
    }

    return 0;
}

実行結果例

--- QMap::keys() を使用 ---
商品名:  "Apple" , 在庫:  100
商品名:  "Banana" , 在庫:  150
商品名:  "Orange" , 在庫:  80

--- QMap::values() を使用 ---
在庫数:  100
在庫数:  150
在庫数:  80

利点

  • 特にキーのリストだけをソートされた順で取得したい場合に便利。
  • キーのみ、または値のみを処理したい場合にコードがシンプルになる。

考慮点

  • キーと値を同時に処理したい場合、keys()でキーリストを取得し、ループ内でvalue(key)を呼び出すと、各要素で検索処理が走るため、非効率になる可能性があります。この場合は、イテレータ(範囲ベースforループを含む)の方が適しています。
  • keys()values()は、元のマップの要素を新しいQListにコピーするため、マップが大きい場合にパフォーマンス上のオーバーヘッドが発生します。

特定のキーに対応する要素にアクセスしたいだけであれば、イテレータを使ってループする必要はありません。

  • contains(const Key& key): キーがマップに存在するかどうかをチェックします。
  • value(const Key& key, const T& defaultValue): キーが存在しない場合、指定されたdefaultValueが返されますが、マップには挿入されません。
  • value(const Key& key): キーが存在しない場合、デフォルトコンストラクタで値が初期化されたものが返されますが、マップには挿入されません。
  • operator[](const Key& key): キーが存在しない場合、デフォルトコンストラクタで値が初期化され、そのキーでマップに新しい要素が挿入されます。書き込みアクセスにも使用できます。
#include <QCoreApplication>
#include <QMap>
#include <QString>
#include <QDebug>

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

    QMap<QString, double> studentGrades;
    studentGrades.insert("Alice", 3.8);
    studentGrades.insert("Bob", 3.2);

    qDebug() << "--- 個別要素アクセス ---";

    // operator[] でアクセス (キーが存在しない場合は挿入される)
    qDebug() << "Aliceの成績 (operator[]): " << studentGrades["Alice"];
    qDebug() << "Charlieの成績 (operator[]): " << studentGrades["Charlie"]; // "Charlie"が挿入され、デフォルト値(0.0)が設定される
    qDebug() << "マップサイズ: " << studentGrades.size(); // 3になる

    // value() でアクセス (キーが存在しない場合でも挿入されない)
    qDebug() << "Bobの成績 (value()): " << studentGrades.value("Bob");
    qDebug() << "Davidの成績 (value()): " << studentGrades.value("David"); // "David"は挿入されない
    qDebug() << "マップサイズ: " << studentGrades.size(); // 3のまま

    // value() とデフォルト値
    qDebug() << "Eveの成績 (value() with default): " << studentGrades.value("Eve", 4.0); // "Eve"は挿入されない
    qDebug() << "マップサイズ: " << studentGrades.size(); // 3のまま

    // contains() で存在チェック
    if (studentGrades.contains("Alice")) {
        qDebug() << "Aliceは存在します。";
    } else {
        qDebug() << "Aliceは存在しません。";
    }

    if (studentGrades.contains("Frank")) {
        qDebug() << "Frankは存在します。";
    } else {
        qDebug() << "Frankは存在しません。";
    }

    // operator[] で値を変更
    studentGrades["Bob"] = 3.5;
    qDebug() << "Bobの新しい成績: " << studentGrades["Bob"];

    return 0;
}

実行結果例

--- 個別要素アクセス ---
Aliceの成績 (operator[]):  3.8
Charlieの成績 (operator[]):  0
マップサイズ:  3
Bobの成績 (value()):  3.2
Davidの成績 (value()):  0
マップサイズ:  3
Eveの成績 (value() with default):  4
マップサイズ:  3
Aliceは存在します。
Frankは存在しません。
Bobの新しい成績:  3.5

利点

  • 特定のキーの値を取得・設定する最も直接的な方法。
  • 単一の要素に直接アクセスしたり、存在をチェックしたりするのに非常に便利。

考慮点

  • operator[]はキーが存在しない場合に自動的に要素を挿入するため、意図しない変更に注意が必要。存在チェックを行いたい場合はcontains()またはfind()を使用する。

QMap::cend()はSTLスタイルイテレータを使用したループの標準的な終わり方ですが、Qtには目的や状況に応じた様々な代替方法が用意されています。

  • キーや値のリスト全体を個別に取得したい場合は、keys()values()が利用できますが、コピーによるオーバーヘッドに注意が必要です。
  • ループ中に要素の追加や削除を頻繁に行う場合は、Javaスタイルイテレータ(特にQMutableMapIterator)が適しているかもしれません。
  • 特定のキーの存在確認や値の取得・設定には、contains()value()operator[]が便利です。
  • 現代的なコードで推奨されるのは、ほとんどの場合C++11の範囲ベースforループです。