Qt QMap徹底解説:key_value_iteratorでキーと値を自在に操作

2025-05-27

QMap::key_value_iterator とは

QMap::key_value_iterator は、QtのコンテナクラスであるQMap(キーと値のペアをキーでソートして格納する連想配列)を反復処理(イテレート)するためのイテレータの一種です。

従来のQMap::iteratorQMap::const_iteratorとは異なり、QMap::key_value_iterator は、デリファレンス(*演算子)したときに、キーと値の両方をstd::pair<const Key, T>(またはそれに相当する型)として返します。

これに対し、従来のQMap::iteratorはデリファレンスすると値のみT&)を返します。このため、従来のイテレータでキーにアクセスするには、it.key()it.value()といったメソッドを明示的に呼び出す必要がありました。

QMap::key_value_iteratorは、C++17で導入された構造化束縛(structured bindings)と組み合わせることで、より簡潔で直感的なコードでキーと値のペアを扱うことができるように設計されました。

特徴と利点

  • 構造化束縛との相性
    C++17以降では、以下のように構造化束縛と組み合わせて、コードをより読みやすく記述できます。

    QMap<QString, int> myMap;
    myMap["one"] = 1;
    myMap["two"] = 2;
    
    // QMap::key_value_iterator を使用した例 (Qt 5.10以降)
    for (auto it = myMap.keyValueBegin(); it != myMap.keyValueEnd(); ++it) {
        // it->first でキー、it->second で値にアクセス
        qDebug() << "Key:" << it->first << ", Value:" << it->second;
    }
    
    // C++17 の asKeyValueRange と構造化束縛を使ったより現代的な方法 (Qt 6.4以降)
    // Qt 5.10 - 6.3 の場合は keyValueBegin()/keyValueEnd() を使用し、
    // for (auto [key, value] : someMap.asKeyValueRange()) { ... } のような形式で記述
    for (auto [key, value] : myMap.asKeyValueRange()) {
        qDebug() << "Key:" << key << ", Value:" << value;
    }
    
  • STLスタイル
    std::mapのイテレータのように振る舞うため、STLのイテレータに慣れている開発者にとって使いやすいです。

  • キーと値の同時アクセス
    *itのようにデリファレンスするだけで、キーと値の両方にアクセスできます。

従来のイテレータとの違い

イテレータの種類* 演算子で返されるものキーへのアクセス方法値へのアクセス方法
QMap::iterator値 (T&)it.key()*it または it.value()
QMap::key_value_iteratorキーと値のペア (std::pair<const Key, T>)it->firstit->second

QMap::key_value_iterator は、QMapオブジェクトの以下のメソッドから取得できます。

  • QMap::constKeyValueEnd(): 定数イテレータを返します。
  • QMap::constKeyValueBegin(): 定数イテレータを返します。
  • QMap::keyValueEnd(): マップの最後の要素の次(終端)を指すイテレータを返します。
  • QMap::keyValueBegin(): マップの最初の要素を指すイテレータを返します。

また、Qt 6.4からはQMap::asKeyValueRange()というヘルパー関数が導入され、範囲ベースforループでキーと値のペアを直接イテレートできるようになり、より簡潔な記述が可能になりました。



イテレータの無効化 (Iterator Invalidation)

問題
QMap::key_value_iteratorを含むQtのSTLスタイルイテレータは、マップの構造を変更する操作(要素の挿入、削除など)が行われると、無効になる可能性があります。無効なイテレータをデリファレンスしたり、使用しようとすると、未定義の動作(クラッシュ、誤ったデータアクセスなど)を引き起こします。


QMap<int, QString> myMap = {{1, "one"}, {2, "two"}, {3, "three"}};

for (auto it = myMap.keyValueBegin(); it != myMap.keyValueEnd(); ++it) {
    if (it->first == 2) {
        myMap.remove(2); // ここでイテレータ `it` は無効になる可能性がある
        // 以降 `it` を使用すると危険
    }
}

トラブルシューティング

  • 一時コピーの利用
    構造を頻繁に変更する場合や、イテレータ無効化の複雑さを避けたい場合は、マップの一時コピーを作成してイテレートすることも検討できます(ただし、パフォーマンスのオーバーヘッドがあります)。
  • 削除後のイテレータの再取得
    要素を削除する必要がある場合は、削除操作を行った後に新しいイテレータを再取得します。QMap::erase()メソッドは、削除後の次の有効なイテレータを返します。
    QMap<int, QString> myMap = {{1, "one"}, {2, "two"}, {3, "three"}};
    auto it = myMap.keyValueBegin();
    while (it != myMap.keyValueEnd()) {
        if (it->first == 2) {
            it = myMap.erase(it); // eraseは次の有効なイテレータを返す
        } else {
            ++it;
        }
    }
    
  • ループ内でマップを変更しない
    イテレータを使用しているループ内でQMapの要素を追加したり削除したりするのを避けるのが最も安全です。

constと非constイテレータの混同

問題
QMap::keyValueBegin()QMap::keyValueEnd()は非constQMap::key_value_iteratorを返しますが、QMap::constKeyValueBegin()QMap::constKeyValueEnd()constQMap::const_key_value_iteratorを返します。これらを混同したり、定数オブジェクトに対して非定数イテレータを使用しようとすると、コンパイルエラーが発生します。


const QMap<int, QString> constMap = {{1, "one"}};
// auto it = constMap.keyValueBegin(); // エラー: constオブジェクトに対して非constイテレータを呼び出せない

// 正しい:
auto it = constMap.constKeyValueBegin();

トラブルシューティング

  • autoキーワードの活用
    C++11以降で利用可能なautoキーワードは、イテレータの型推論に役立ち、このような間違いを減らすことができます。
    QMap<int, QString> myMap;
    for (auto it = myMap.keyValueBegin(); it != myMap.keyValueEnd(); ++it) { /* ... */ }
    
    const QMap<int, QString> constMap;
    for (auto it = constMap.constKeyValueBegin(); it != constMap.constKeyValueEnd(); ++it) { /* ... */ }
    
  • constオブジェクトにはconstイテレータを使用する
    constQMapをイテレートする場合は、常にconstKeyValueBegin()constKeyValueEnd()を使用してください。

一時オブジェクトに対するイテレータの使用

問題
関数呼び出しの戻り値として一時的に生成されたQMapオブジェクトに対して、直接keyValueBegin()keyValueEnd()を呼び出してイテレータを取得し、それを保持しようとすると、その一時オブジェクトがスコープを抜けて破棄された際にイテレータがダングリングポインタ(無効なメモリを指すポインタ)になり、クラッシュを引き起こす可能性があります。


QMap<int, QString> createMap() {
    return {{1, "a"}, {2, "b"}};
}

// 危険な例
auto it_begin = createMap().keyValueBegin(); // createMap()が返すQMapは一時オブジェクト
// この行の実行後、一時QMapは破棄され、it_beginは無効になる
// auto it_end = createMap().keyValueEnd(); // 同様に無効

// *it_begin; // クラッシュの原因となる

トラブルシューティング

  • Qt 6.4以降のasKeyValueRange()の利用
    Qt 6.4以降で導入されたasKeyValueRange()は、この問題をより安全に扱うためのラッパーを提供します。
    // より安全な例 (Qt 6.4以降)
    for (auto [key, value] : createMap().asKeyValueRange()) {
        qDebug() << key << value;
    }
    
    これは一時オブジェクトの寿命を延長するような動作をするため、安全に一時オブジェクトをイテレートできます。
  • 一時オブジェクトを明示的に変数に格納する
    一時的に生成されたQMapをイテレートする場合は、まずそれをローカル変数にコピーまたはムーブしてからイテレータを取得します。
    QMap<int, QString> myMap = createMap(); // ローカル変数にコピー
    for (auto it = myMap.keyValueBegin(); it != myMap.keyValueEnd(); ++it) {
        qDebug() << it->first << it->second;
    }
    

構造化束縛での値の変更(誤解)

問題
C++17の構造化束縛(for (auto [key, value] : myMap.asKeyValueRange())など)を使用する際に、valueを変更しても元のマップが更新されないと誤解することがあります。QMap::key_value_iteratorは、*itstd::pair<const Key, T>を返すため、valueの部分は通常T&(値への参照)になります。したがって、valueを変更すると元のマップの値も変更されます。しかし、keyconst Keyなので変更できません。


QMap<QString, int> myMap = {{"A", 1}, {"B", 2}};

for (auto [key, value] : myMap.asKeyValueRange()) {
    value++; // これは元のmyMapの値を変更する
    // key = "C"; // これはコンパイルエラー (keyはconst)
}
qDebug() << myMap; // 出力: QMap(("A", 2)("B", 3))

トラブルシューティング

  • キーの変更は不可: キーはconstであるため、イテレーション中に直接キーを変更することはできません。キーを変更するには、一度その要素を削除し、新しいキーと値のペアで再挿入する必要があります。
  • 参照であることを理解する
    key_value_iteratorが返すペアのvalueは参照であるため、変更が元のマップに反映されることを理解しておきましょう。意図しない変更を避けたい場合は、const auto [key, value] : myMap.asKeyValueRange()のようにconstを付けるか、値渡しでコピーを受け取るようにしてください。

問題
QMapのキーの型(Key)は、全順序を定義するoperator<()を提供する必要があります。これはQMapが内部でキーをソートして保持するために必要だからです。このoperator<()が提供されていないか、正しく定義されていない場合、コンパイルエラーや予期せぬ動作(マップ内の要素が正しくソートされない、要素が見つからないなど)が発生する可能性があります。

  • ポインタをキーにする場合
    Qt 5.8.1以降では、ポインタ型をキーとして安全に使用できますが、それ以前のバージョンや、ポインタ値ではなくポインタが指す内容でソートしたい場合は、カスタムのoperator<()を提供する必要があります。
  • カスタムクラスをキーにする場合
    独自のカスタムクラスをQMapのキーとして使用する場合は、そのクラスに必ずoperator<()をオーバーロードしてください。
    class MyKey {
    public:
        int id;
        QString name;
    
        bool operator<(const MyKey& other) const {
            if (id != other.id) {
                return id < other.id;
            }
            return name < other.name;
        }
        // 他の必要なコンストラクタ、メンバーなど
    };
    
    QMap<MyKey, QString> myCustomMap;
    


QMap::key_value_iteratorの基本

QMap::key_value_iteratorは、QMap内のキーと値のペアを一緒に反復処理するためのイテレータです。従来のQMap::iteratorが値のみを返すのに対し、key_value_iteratorはデリファレンス(*it)すると、キーと値のペア(通常はstd::pair<const Key, T>に相当)を返します。

このイテレータは、C++17で導入された構造化束縛(structured bindings)と組み合わせることで、非常に簡潔で読みやすいコードを書くことができます。

例1: keyValueBegin()keyValueEnd() を使用した基本的なイテレーション

最も基本的な使用例です。QMap::keyValueBegin()で開始イテレータを、QMap::keyValueEnd()で終了イテレータを取得し、ループでマップ内の全ての要素を処理します。

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

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

    QMap<QString, int> fruits;
    fruits["Apple"] = 50;
    fruits["Banana"] = 30;
    fruits["Cherry"] = 70;
    fruits["Date"] = 20;

    qDebug() << "--- マップの要素をkey_value_iteratorで表示 ---";
    // keyValueBegin() と keyValueEnd() を使用
    for (auto it = fruits.keyValueBegin(); it != fruits.keyValueEnd(); ++it) {
        // it->first でキー、it->second で値にアクセス
        qDebug() << "Key:" << it->first << ", Value:" << it->second;
    }

    // Qt 6.4以降で推奨される asKeyValueRange() の使い方 (より簡潔)
    // Qt 5.10から6.3では keyValueBegin()/keyValueEnd() を明示的に使って範囲ベースforを書く
    qDebug() << "\n--- asKeyValueRange() と構造化束縛で表示 (C++17以降) ---";
    for (auto [fruitName, quantity] : fruits.asKeyValueRange()) {
        qDebug() << "Fruit:" << fruitName << ", Quantity:" << quantity;
    }

    return a.exec();
}

出力例

--- マップの要素をkey_value_iteratorで表示 ---
Key: "Apple" , Value: 50
Key: "Banana" , Value: 30
Key: "Cherry" , Value: 70
Key: "Date" , Value: 20

--- asKeyValueRange() と構造化束縛で表示 (C++17以降) ---
Fruit: "Apple" , Quantity: 50
Fruit: "Banana" , Quantity: 30
Fruit: "Cherry" , Quantity: 70
Fruit: "Date" , Quantity: 20

解説

  • fruits.asKeyValueRange()はQt 6.4で導入されたヘルパー関数で、範囲ベースforループで構造化束縛を使う場合に非常に便利です。これがない場合でも、for (auto it = fruits.keyValueBegin(); it != fruits.keyValueEnd(); ++it) の形式でkey_value_iteratorを使うことができます。
  • it->first でキー(QString型)、it->second で値(int型)にアクセスします。
  • auto it = fruits.keyValueBegin(); でイテレータを取得します。autoを使用すると、QMap<QString, int>::key_value_iteratorという長い型名を省略できます。

例2: constマップとconst_key_value_iterator

constQMapをイテレートする場合、const_key_value_iteratorを使用する必要があります。constKeyValueBegin()constKeyValueEnd()を使います。

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

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

    const QMap<int, QString> errorCodes = {
        {100, "Informational"},
        {200, "Success"},
        {404, "Not Found"},
        {500, "Internal Server Error"}
    };

    qDebug() << "--- 定数マップの要素をconst_key_value_iteratorで表示 ---";
    // constKeyValueBegin() と constKeyValueEnd() を使用
    for (auto it = errorCodes.constKeyValueBegin(); it != errorCodes.constKeyValueEnd(); ++it) {
        qDebug() << "Code:" << it->first << ", Message:" << it->second;
    }

    // 定数マップでの asKeyValueRange() と構造化束縛
    qDebug() << "\n--- 定数マップとasKeyValueRange() + 構造化束縛で表示 ---";
    for (const auto [code, message] : errorCodes.asKeyValueRange()) { // const auto を使うと変更不可
        qDebug() << "Error Code:" << code << ", Description:" << message;
        // code = 0; // これはコンパイルエラー: const なので変更できない
        // message = "New Message"; // これはコンパイルエラー: const なので変更できない
    }

    return a.exec();
}

出力例

--- 定数マップの要素をconst_key_value_iteratorで表示 ---
Code: 100 , Message: "Informational"
Code: 200 , Message: "Success"
Code: 404 , Message: "Not Found"
Code: 500 , Message: "Internal Server Error"

--- 定数マップとasKeyValueRange() + 構造化束縛で表示 ---
Error Code: 100 , Description: "Informational"
Error Code: 200 , Description: "Success"
Error Code: 404 , Description: "Not Found"
Error Code: 500 , Description: "Internal Server Error"

解説

  • 構造化束縛でconst auto [code, message]とすると、codemessageconst参照となり、ループ内でそれらを変更しようとするとコンパイルエラーになります。
  • const QMap<int, QString> errorCodes; のようにconstで宣言されたマップには、変更が許されないconst_key_value_iteratorしか使用できません。

key_value_iteratorは非constの場合、値の参照を得られるため、ループ内で値を変更できます。要素の削除にはQMap::erase()を使用し、削除後の次の有効なイテレータを取得します。

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

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

    QMap<QString, double> itemPrices = {
        {"Laptop", 1200.00},
        {"Mouse", 25.50},
        {"Keyboard", 75.00},
        {"Monitor", 300.00}
    };

    qDebug() << "--- 値の変更 ---";
    // 10% 値上げ
    for (auto it = itemPrices.keyValueBegin(); it != itemPrices.keyValueEnd(); ++it) {
        if (it->first == "Mouse") {
            it->second *= 1.20; // マウスの価格を20%上げる
        } else {
            it->second *= 1.10; // それ以外の価格を10%上げる
        }
    }
    qDebug() << "更新後の価格:";
    for (auto [item, price] : itemPrices.asKeyValueRange()) {
        qDebug() << item << ":" << price;
    }

    qDebug() << "\n--- 要素の削除 ---";
    // 値段が300未満のアイテムを削除
    auto it = itemPrices.keyValueBegin();
    while (it != itemPrices.keyValueEnd()) {
        if (it->second < 300.0) {
            qDebug() << "Deleting:" << it->first << "with price" << it->second;
            it = itemPrices.erase(it); // eraseは次の有効なイテレータを返す
        } else {
            ++it;
        }
    }

    qDebug() << "\n削除後のアイテム:";
    for (auto [item, price] : itemPrices.asKeyValueRange()) {
        qDebug() << item << ":" << price;
    }

    return a.exec();
}

出力例

--- 値の変更 ---
更新後の価格:
"Keyboard" : 82.5
"Laptop" : 1320
"Monitor" : 330
"Mouse" : 30.6

--- 要素の削除 ---
Deleting: "Keyboard" with price 82.5
Deleting: "Mouse" with price 30.6

削除後のアイテム:
"Laptop" : 1320
"Monitor" : 330
  • while (it != itemPrices.keyValueEnd()) ループでは、要素が削除された場合は++itを行わないことに注意してください。erase()が既に次のイテレータを返しているため、二重に進めてしまうことになります。
  • 要素の削除
    ループ内で要素を削除する場合、イテレータが無効になる問題が発生します。QMap::erase(it)は、指定されたイテレータの要素を削除し、次の有効なイテレータを返すため、その戻り値を使ってイテレータを更新することで安全にループを続行できます。
  • 値の変更
    it->secondは値への参照であるため、it->second *= 1.10;のように代入を行うと、元のQMap内の値が直接更新されます。


従来の QMap::iterator と QMap::const_iterator を使用する方法

これはQMap::key_value_iteratorが導入される前から存在する伝統的な方法です。デリファレンスすると値のみを返します。

特徴

  • it.key() と it.value() でキーと値にアクセス
    キーにアクセスするにはit.key()メソッドを明示的に呼び出す必要があります。値にはit.value()でもアクセスできます。
  • *it で値にアクセス
    *it はマップ内の値(T&またはconst T&)を返します。

使用例

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

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

    QMap<QString, int> scores;
    scores["Alice"] = 95;
    scores["Bob"] = 88;
    scores["Charlie"] = 72;

    qDebug() << "--- 従来のQMap::iteratorを使用 ---";
    for (QMap<QString, int>::iterator it = scores.begin(); it != scores.end(); ++it) {
        qDebug() << "Key:" << it.key() << ", Value:" << it.value();
        // または qDebug() << "Key:" << it.key() << ", Value:" << *it;
    }

    qDebug() << "\n--- 従来のQMap::const_iteratorを使用 ---";
    const QMap<QString, int> constScores = scores;
    for (QMap<QString, int>::const_iterator it = constScores.begin(); it != constScores.end(); ++it) {
        qDebug() << "Key:" << it.key() << ", Value:" << it.value();
    }

    return a.exec();
}

利点

  • 値のみを操作する場合にコードが若干シンプルになることがある。
  • 互換性が高い(古いQtバージョンでも利用可能)。

欠点

  • 構造化束縛と直接連携できない。
  • キーと値を同時に扱う際にit.key()it.value()(または*it)を呼び出す必要があり、やや冗長。

キーリストと値リストを別々に取得する方法

QMap::keys()QMap::values()メソッドを使って、キーと値をそれぞれ別のQListとして取得し、それをイテレートする方法です。

特徴

  • ループ内でマップを頻繁に変更するような場合に、イテレータ無効化の心配が少ない。
  • マップの要素順序は保証される(QMapはキーでソートされるため、keys()values()は同じ順序で要素を返す)。

使用例

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

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

    QMap<int, QString> statusMessages;
    statusMessages[200] = "OK";
    statusMessages[400] = "Bad Request";
    statusMessages[404] = "Not Found";
    statusMessages[500] = "Internal Server Error";

    qDebug() << "--- キーリストと値リストを別々に取得 ---";
    QList<int> keys = statusMessages.keys();
    QList<QString> values = statusMessages.values();

    for (int i = 0; i < keys.size(); ++i) {
        qDebug() << "Code:" << keys.at(i) << ", Message:" << values.at(i);
    }

    return a.exec();
}

利点

  • 特定のキーや値のリストだけが必要な場合に便利。
  • イテレータ無効化の心配が少ない。

欠点

  • キーと値のペアを同時に扱うには、インデックスを共有する必要があり、コードが読みにくくなることがある。
  • マップの要素数が非常に多い場合、QListのコピーが作成されるため、メモリとパフォーマンスのオーバーヘッドが発生する。

C++11の範囲ベースforループ(Qt 5.10以前のQMap::key_value_iteratorが使えない場合)

QMapbegin()end()メソッドを提供しているため、C++11以降の範囲ベースforループを使用できます。ただし、これはQMap::iteratorと同じように値のみを返します。キーにアクセスするにはit.key()が必要です。

使用例

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

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

    QMap<QString, double> productPrices;
    productPrices["Laptop"] = 1200.0;
    productPrices["Mouse"] = 25.0;
    productPrices["Keyboard"] = 75.0;

    qDebug() << "--- 範囲ベースforループ (値のみ) ---";
    // 範囲ベースforループでは、イテレータの型は自動的に推論される
    // QMapのイテレータはデリファレンスで値を返すため、'price'は値そのもの
    for (double price : productPrices) { // ここで直接キーにはアクセスできない
        // priceは値そのもの
        // 例えば、キーを知るためには別の方法が必要
        // qDebug() << "Price:" << price; // これだけだとキーが不明
    }

    qDebug() << "\n--- 範囲ベースforループとit.key()を組み合わせる場合 ---";
    // QMap::iterator を返す begin() と end() の動作を利用する
    for (auto it = productPrices.begin(); it != productPrices.end(); ++it) {
        qDebug() << "Product:" << it.key() << ", Price:" << *it; // *it は値
    }

    return a.exec();
}

利点

  • C++11以降で標準的に利用できる。
  • コードが簡潔で読みやすい(特に値のみを扱う場合)。

欠点

  • QMap::key_value_iteratorと比べると、キーと値のペアの同時処理のコードがやや冗長。
  • 直接キーにアクセスできないため、it.key()を明示的に呼び出す必要がある。

QtにはQMap専用のJavaスタイルイテレータであるQMapIteratorも存在します。これは特に、スナップショット的なイテレーションが必要な場合や、イテレータ無効化の問題を避けたい場合に有用です。QMapIteratorはコンストラクタで渡されたマップのスナップショット(コピーではないが、イテレーション中にマップが変更されても影響を受けない)に対して動作します。

特徴

  • スナップショット動作
    イテレータの作成後にマップが変更されても、イテレータ自身の状態は影響を受けない。
  • Javaスタイル
    hasNext(), next(), key(), value() などのメソッドを使用。

使用例

#include <QCoreApplication>
#include <QMap>
#include <QMapIterator>
#include <QDebug>

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

    QMap<QString, int> inventory;
    inventory["Widgets"] = 100;
    inventory["Gadgets"] = 50;
    inventory["Doodads"] = 75;

    qDebug() << "--- QMapIteratorを使用 ---";
    QMapIterator<QString, int> i(inventory);
    while (i.hasNext()) {
        i.next(); // 次の要素に進める
        qDebug() << "Item:" << i.key() << ", Stock:" << i.value();
    }

    // QMapIterator作成後にマップを変更しても問題ない例
    qDebug() << "\n--- QMapIterator作成後のマップ変更 ---";
    QMapIterator<QString, int> j(inventory);
    inventory["New Item"] = 20; // マップに新しい要素を追加

    while (j.hasNext()) {
        j.next();
        qDebug() << "Item (old snapshot):" << j.key() << ", Stock:" << j.value();
    }
    qDebug() << "現在のマップ:" << inventory;

    return a.exec();
}

出力例

--- QMapIteratorを使用 ---
Item: "Doodads" , Stock: 75
Item: "Gadgets" , Stock: 50
Item: "Widgets" , Stock: 100

--- QMapIterator作成後のマップ変更 ---
Item (old snapshot): "Doodads" , Stock: 75
Item (old snapshot): "Gadgets" , Stock: 50
Item (old snapshot): "Widgets" , Stock: 100
現在のマップ: QMap(("Doodads", 75)("Gadgets", 50)("New Item", 20)("Widgets", 100))

利点

  • 他のJavaスタイルのイテレータに慣れている場合に直感的。
  • イテレータ作成後のマップ変更によるイテレータ無効化を心配する必要がない。
  • イテレータ作成時にマップのコピーまたは内部表現のコピーが作成されるため、大規模なマップではパフォーマンスやメモリのオーバーヘッドが発生する可能性がある(ただし、Qt 6ではコピーがより効率的になった)。
  • key_value_iteratorや範囲ベースforループと比較して、コードがやや冗長になることがある。
  • キーまたは値のリストだけが必要な場合
    QMap::keys()QMap::values() を使用します。
  • イテレータ無効化を絶対に避けたい、またはJavaスタイルに慣れている場合
    QMapIterator を検討します。
  • 古いQtバージョンやC++11まで
    従来の QMap::iterator を使用し、it.key()it.value() を呼び出す方法。
  • 最も推奨される方法(Qt 5.10以降、C++17推奨)
    QMap::key_value_iterator を使用し、特に QMap::asKeyValueRange() と構造化束縛を組み合わせるのが、現代的で最も簡潔かつ安全な方法です。