【Qtプログラミング】QList::operator!=()を使いこなす:コード例とデバッグのコツ

2025-06-06

QList::operator!=() は、Qt の QList クラスに定義されている比較演算子で、2つの QList オブジェクトが等しくないかどうかを判定するために使用されます。

この演算子は、以下のように動作します。

  1. 要素数の比較: まず、2つの QList オブジェクトの要素数が比較されます。要素数が異なる場合、それらのリストは等しくないと判断され、true が返されます。

  2. 要素ごとの比較: 要素数が同じである場合、リスト内のすべての要素が順に比較されます。要素の比較には、その要素の型が提供する operator==() (等価演算子) が使用されます。

    • もし、対応する位置にあるいずれかの要素が等しくない場合、そのリストは等しくないと判断され、true が返されます。
  3. すべてが等しい場合: 要素数もすべての要素も等しい場合、リストは等しいと判断され、false が返されます。これは operator!=() なので、「等しくない」という条件が満たされないためです。

要するに、list1 != list2!(list1 == list2) と同じ意味になります。operator==() がすべての要素が完全に一致する場合に true を返すのに対し、operator!=() は一つでも異なる点があれば true を返します。

使用例

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

int main() {
    QList<int> list1;
    list1 << 1 << 2 << 3;

    QList<int> list2;
    list2 << 1 << 2 << 3;

    QList<int> list3;
    list3 << 4 << 5 << 6;

    QList<int> list4;
    list4 << 1 << 2; // 要素数が異なる

    // list1 と list2 の比較
    if (list1 != list2) {
        qDebug() << "list1 と list2 は等しくありません。"; // この行は実行されない
    } else {
        qDebug() << "list1 と list2 は等しいです。"; // 出力: "list1 と list2 は等しいです。"
    }

    // list1 と list3 の比較
    if (list1 != list3) {
        qDebug() << "list1 と list3 は等しくありません。"; // 出力: "list1 と list3 は等しくありません。"
    } else {
        qDebug() << "list1 と list3 は等しいです。";
    }

    // list1 と list4 の比較 (要素数が異なるケース)
    if (list1 != list4) {
        qDebug() << "list1 と list4 は等しくありません。"; // 出力: "list1 と list4 は等しくありません。"
    } else {
        qDebug() << "list1 と list4 は等しいです。";
    }

    return 0;
}


QList::operator!=() 自体は比較的シンプルで、一般的な比較演算子と同様に機能します。しかし、比較対象となる要素の型や、リストの扱い方によっては、意図しない結果やエラーが発生することがあります。

比較対象の要素型に operator==() が定義されていない、または不適切に定義されている

QList::operator!=() は内部的に、リスト内の各要素に対して operator==() (等価演算子) を使用して比較を行います。もし、QList がカスタムクラスや構造体を格納している場合、その型に適切な operator==() が定義されていないと、コンパイルエラーになったり、期待通りの比較が行われなかったりします。

エラーの症状

  • 2つのリストが内容的に同じなのに !=true を返す(またはその逆)。
  • no match for 'operator==' のようなコンパイルエラー。

トラブルシューティング

  • ポインタの比較に注意
    QList<MyObject*> のようにポインタを格納している場合、デフォルトの operator==() はポインタのアドレスを比較します。これは、指し示すオブジェクトの内容ではなく、メモリ上の位置が同じかどうかを意味します。オブジェクトの内容で比較したい場合は、以下のようにします。

    QList<MyObject*> listA;
    QList<MyObject*> listB;
    // ... ポインタとオブジェクトを追加 ...
    
    // 内容で比較したい場合 (手動でループするか、Qtのアルゴリズムを利用)
    bool areNotEqual = false;
    if (listA.size() != listB.size()) {
        areNotEqual = true;
    } else {
        for (int i = 0; i < listA.size(); ++i) {
            // ポインタが有効で、かつオブジェクトの内容が等しくない場合
            if (listA.at(i) && listB.at(i) && !(*listA.at(i) == *listB.at(i))) {
                areNotEqual = true;
                break;
            }
            // または、どちらかのポインタが無効である場合(例: null)
            if ((listA.at(i) && !listB.at(i)) || (!listA.at(i) && listB.at(i))) {
                areNotEqual = true;
                break;
            }
        }
    }
    
    if (areNotEqual) {
        qDebug() << "内容的に等しくありません。";
    }
    

    Qt 6からは、std::equalのような標準アルゴリズムとラムダ式を組み合わせることで、より簡潔に記述できます。

  • カスタム型に operator==() を定義する
    QList に格納するカスタムクラスや構造体に対して、const 参照を受け取り、bool を返す operator==() を定義します。必要であれば operator!=() も定義すると良いでしょう。

    class MyCustomObject {
    public:
        int id;
        QString name;
    
        // 等価演算子の定義
        bool operator==(const MyCustomObject& other) const {
            return (id == other.id && name == other.name);
        }
    
        // 不等価演算子 (operator==()があれば、通常は自動的に機能するが、明示的に定義も可能)
        bool operator!=(const MyCustomObject& other) const {
            return !(*this == other);
        }
    };
    
    // 使用例
    QList<MyCustomObject> listA;
    QList<MyCustomObject> listB;
    // ... 要素を追加 ...
    if (listA != listB) {
        // ...
    }
    

リストの順序が異なる

QList::operator!=() は、要素の「順序」も比較の対象とします。要素の内容が全く同じでも、順序が異なれば true を返します。

エラーの症状

  • 「同じ内容のはずなのに等しくない」と判定される。

トラブルシューティング

  • これはエラーというよりは仕様です。もし順序を無視して「含まれる要素が同じかどうか」を比較したい場合は、QSet を使用したり、一度ソートしてから比較したり、手動で要素の存在を確認するロジックを実装する必要があります。

    QList<int> listA = {1, 2, 3};
    QList<int> listB = {3, 2, 1};
    
    if (listA != listB) {
        qDebug() << "順序が異なるため、等しくないと判定されます。"; // これが出力される
    }
    
    // 順序を無視して要素が同じか確認する場合の例
    QSet<int> setA = listA.toSet();
    QSet<int> setB = listB.toSet();
    
    if (setA != setB) { // QSetの比較は順序を無視する
        qDebug() << "要素の集合は等しくありません。";
    } else {
        qDebug() << "要素の集合は等しいです。"; // これが出力される
    }
    

リストのライフサイクルとコピー

Qtのコンテナは「暗黙的な共有 (Implicit Sharing)」というメカニズムを使用しています。これは、リストがコピーされたときに、実際にデータがコピーされるのではなく、同じデータへの参照が共有されるというものです。データが変更されたときに初めて、ディープコピーが行われます(CoW: Copy-on-Write)。

通常、これはパフォーマンス上の利点であり、operator!=() の動作に直接的な問題を引き起こすことはありません。しかし、非常に特殊なケースや、デバッグ中に内部的な動作を誤解すると混乱する可能性があります。

トラブルシューティング

  • ただし、iteratorを使用中にリストを変更すると、iteratorが無効になる可能性があるため注意が必要です。operator!=() はiteratorを直接使用しないため、この問題は通常発生しません。
  • ほとんどの場合、暗黙的な共有を意識する必要はありません。QList を通常のC++オブジェクトのように扱って問題ありません。

QList の内容が期待通りに設定されていない

これは operator!=() 自体の問題ではありませんが、比較結果が期待と異なる場合、そもそもリストの内容が正しくない可能性があります。

エラーの症状

  • list1 != list2 としたときに、期待される結果と異なる結果が得られる。

トラブルシューティング

  • 要素がカスタム型の場合は、そのカスタム型の operator<< (QDebug用) を定義しておくと、デバッグ出力が容易になります。

    // MyCustomObject のデバッグ出力オペレータを定義
    QDebug operator<<(QDebug debug, const MyCustomObject& obj) {
        QDebugStateSaver saver(debug);
        debug.nospace() << "MyCustomObject(id=" << obj.id << ", name='" << obj.name << "')";
        return debug;
    }
    
    // 使用例
    QList<MyCustomObject> my_list;
    my_list << MyCustomObject{1, "Apple"} << MyCustomObject{2, "Banana"};
    qDebug() << "My List:" << my_list;
    
  • qDebug() を使って、比較を行う前に両方の QList の内容(要素数と各要素の値)を出力して確認します。



QList::operator!=() は、2つの QList オブジェクトが「等しくない」ことを比較するための演算子です。等しくないとは、以下のいずれかの条件を満たす場合を指します。

  1. 要素の数が異なる。
  2. 要素の数が同じだが、対応する位置の要素の少なくとも1つが異なる。
  3. 要素の数が同じで、すべての要素の内容も同じだが、順序が異なる。

基本的な使い方から、カスタム型での注意点まで、いくつかの例を見ていきましょう。

例1: 基本的な数値の QList の比較

最も一般的なケースで、組み込み型 (int, QString など) を格納する QList の比較です。

#include <QList>
#include <QString>
#include <QDebug> // qDebug() を使用するために必要

int main() {
    qDebug() << "--- 例1: 基本的な数値の QList の比較 ---";

    // ケース A: 内容が完全に同じリスト
    QList<int> listA1;
    listA1 << 10 << 20 << 30;

    QList<int> listA2;
    listA2 << 10 << 20 << 30;

    if (listA1 != listA2) {
        qDebug() << "listA1 と listA2 は等しくありません。(実際は等しい)";
    } else {
        qDebug() << "listA1 と listA2 は等しいです。"; // この行が出力される
    }

    // ケース B: 要素の順序が異なるリスト
    QList<int> listB1;
    listB1 << 10 << 20 << 30;

    QList<int> listB2;
    listB2 << 30 << 20 << 10; // 順序が異なる

    if (listB1 != listB2) {
        qDebug() << "listB1 と listB2 は等しくありません。(順序が異なるため)"; // この行が出力される
    } else {
        qDebug() << "listB1 と listB2 は等しいです。";
    }

    // ケース C: 要素の数が異なるリスト
    QList<int> listC1;
    listC1 << 10 << 20 << 30;

    QList<int> listC2;
    listC2 << 10 << 20; // 要素数が少ない

    if (listC1 != listC2) {
        qDebug() << "listC1 と listC2 は等しくありません。(要素数が異なるため)"; // この行が出力される
    } else {
        qDebug() << "listC1 と listC2 は等しいです。";
    }

    // ケース D: 要素の値が異なるリスト
    QList<QString> listD1;
    listD1 << "Apple" << "Banana" << "Cherry";

    QList<QString> listD2;
    listD2 << "Apple" << "Grape" << "Cherry"; // Banana と Grape が異なる

    if (listD1 != listD2) {
        qDebug() << "listD1 と listD2 は等しくありません。(要素の値が異なるため)"; // この行が出力される
    } else {
        qDebug() << "listD1 と listD2 は等しいです。";
    }

    return 0;
}

解説
上記の例からわかるように、QList::operator!=() は非常に厳密な比較を行います。要素の数、内容、そして順序のすべてが一致しなければ「等しい」とは判定されず、一つでも異なれば true (等しくない) を返します。

例2: カスタム型を格納する QList の比較

QList が独自のクラスや構造体 (MyObject など) のオブジェクトを格納する場合、そのカスタム型に operator==() を適切に定義する必要があります。operator!=()operator==() の結果を反転させるだけなので、operator==() の定義が最も重要です。

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

// カスタムクラスの定義
class Product {
public:
    int id;
    QString name;
    double price;

    // コンストラクタ
    Product(int id = 0, const QString& name = "", double price = 0.0)
        : id(id), name(name), price(price) {}

    // 等価演算子 (operator==) を定義する
    // これが QList::operator!=() の内部で使われる
    bool operator==(const Product& other) const {
        return (this->id == other.id &&
                this->name == other.name &&
                this->price == other.price);
    }

    // 不等価演算子 (operator!=) は operator== を使って実装するのが一般的
    // これを定義しなくても、QList::operator!=() は operator== の結果を反転して使用する
    bool operator!=(const Product& other) const {
        return !(*this == other);
    }
};

// QDebug で Product オブジェクトを表示するためのストリーム演算子 (任意だがデバッグに便利)
QDebug operator<<(QDebug debug, const Product& p) {
    QDebugStateSaver saver(debug); // QDebug の状態を保存・復元
    debug.nospace() << "Product(id=" << p.id
                    << ", name='" << p.name << "'"
                    << ", price=" << p.price << ")";
    return debug;
}


int main() {
    qDebug() << "--- 例2: カスタム型を格納する QList の比較 ---";

    QList<Product> products1;
    products1 << Product(1, "Laptop", 1200.0)
              << Product(2, "Mouse", 25.0)
              << Product(3, "Keyboard", 75.0);

    QList<Product> products2;
    products2 << Product(1, "Laptop", 1200.0)
              << Product(2, "Mouse", 25.0)
              << Product(3, "Keyboard", 75.0);

    // ケース A: 内容が完全に同じリスト
    if (products1 != products2) {
        qDebug() << "products1 と products2 は等しくありません。(実際は等しい)";
    } else {
        qDebug() << "products1 と products2 は等しいです。"; // この行が出力される
    }

    // ケース B: 要素の値が異なるリスト
    QList<Product> products3;
    products3 << Product(1, "Laptop", 1200.0)
              << Product(2, "Mouse", 25.0)
              << Product(99, "Monitor", 300.0); // IDと名前が異なる

    if (products1 != products3) {
        qDebug() << "products1 と products3 は等しくありません。(要素の値が異なるため)"; // この行が出力される
        qDebug() << "products1:" << products1;
        qDebug() << "products3:" << products3;
    } else {
        qDebug() << "products1 と products3 は等しいです。";
    }

    // ケース C: 要素の順序が異なるリスト
    QList<Product> products4;
    products4 << Product(3, "Keyboard", 75.0) // 順序が異なる
              << Product(1, "Laptop", 1200.0)
              << Product(2, "Mouse", 25.0);

    if (products1 != products4) {
        qDebug() << "products1 と products4 は等しくありません。(順序が異なるため)"; // この行が出力される
        qDebug() << "products1:" << products1;
        qDebug() << "products4:" << products4;
    } else {
        qDebug() << "products1 と products4 は等しいです。";
    }

    return 0;
}

解説
カスタム型 Productoperator==() を定義することで、QList はその定義に従って要素を比較できるようになります。もし operator==() を定義しなかった場合、QList はコンパイルエラーになるか、デフォルトのメンバーごとの比較(あるいはポインタであればアドレス比較)を試み、意図しない結果を招く可能性があります。operator!=()operator==() が適切に定義されていれば、その結果を反転するだけで正しく機能します。

例3: ポインタを格納する QList の比較(注意が必要)

QList<MyObject*> のようにポインタを格納している場合、QList::operator!=() はデフォルトでポインタのアドレスを比較します。これは、ポインタが指すオブジェクトの内容ではなく、**メモリ上のポインタの値(アドレス)**が異なるかどうかを意味します。オブジェクトの内容で比較したい場合は、手動で比較ロジックを記述する必要があります。

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

class DataObject {
public:
    int value;
    QString label;

    DataObject(int v = 0, const QString& l = "") : value(v), label(l) {}

    // DataObject の内容の等価演算子 (ポインタが指すオブジェクトの内容比較に必要)
    bool operator==(const DataObject& other) const {
        return (this->value == other.value && this->label == other.label);
    }

    // QDebug で DataObject オブジェクトを表示するためのストリーム演算子
    QDebug operator<<(QDebug debug, const DataObject& obj) {
        QDebugStateSaver saver(debug);
        debug.nospace() << "DataObject(value=" << obj.value << ", label='" << obj.label << "')";
        return debug;
    }
};

int main() {
    qDebug() << "--- 例3: ポインタを格納する QList の比較 (注意が必要) ---";

    DataObject* obj1 = new DataObject(1, "Alpha");
    DataObject* obj2 = new DataObject(2, "Beta");
    DataObject* obj3 = new DataObject(1, "Alpha"); // obj1 と内容は同じだが、別のアドレス

    QList<DataObject*> ptrList1;
    ptrList1 << obj1 << obj2;

    QList<DataObject*> ptrList2;
    ptrList2 << obj1 << obj2; // obj1 と obj2 と同じポインタを格納

    QList<DataObject*> ptrList3;
    ptrList3 << obj3 << obj2; // obj3 は obj1 と内容は同じだがアドレスが異なる

    // ケース A: ポインタのアドレスが完全に同じ場合
    if (ptrList1 != ptrList2) {
        qDebug() << "ptrList1 と ptrList2 は等しくありません。(実際はポインタアドレスが等しい)";
    } else {
        qDebug() << "ptrList1 と ptrList2 は等しいです。(同じポインタを指している)"; // この行が出力される
    }

    // ケース B: 内容は同じだが、ポインタのアドレスが異なる場合
    if (ptrList1 != ptrList3) {
        qDebug() << "ptrList1 と ptrList3 は等しくありません。(obj1 と obj3 は内容が同じでもアドレスが異なるため)"; // この行が出力される
        qDebug() << "ptrList1 の 0番目の要素のアドレス:" << ptrList1.at(0);
        qDebug() << "ptrList3 の 0番目の要素のアドレス:" << ptrList3.at(0);
        qDebug() << "obj1 の内容:" << *obj1;
        qDebug() << "obj3 の内容:" << *obj3;
    } else {
        qDebug() << "ptrList1 と ptrList3 は等しいです。";
    }

    //  ポインタが指すオブジェクトの内容で比較したい場合の例 
    bool contentAreNotEqual = false;
    if (ptrList1.size() != ptrList3.size()) {
        contentAreNotEqual = true;
    } else {
        for (int i = 0; i < ptrList1.size(); ++i) {
            // nullptr チェックも重要
            if (ptrList1.at(i) == nullptr && ptrList3.at(i) == nullptr) {
                // 両方とも nullptr なら等しいとみなす
                continue;
            }
            if (ptrList1.at(i) == nullptr || ptrList3.at(i) == nullptr) {
                // 片方だけ nullptr なら等しくない
                contentAreNotEqual = true;
                break;
            }
            // ポインタが指す内容を比較
            if (!(*ptrList1.at(i) == *ptrList3.at(i))) {
                contentAreNotEqual = true;
                break;
            }
        }
    }

    if (contentAreNotEqual) {
        qDebug() << "ptrList1 と ptrList3 は、内容的には等しくありません。"; // この行が出力される
    } else {
        qDebug() << "ptrList1 と ptrList3 は、内容的には等しいです。";
    }

    // メモリの解放
    delete obj1;
    delete obj2;
    delete obj3;

    return 0;
}

解説
ポインタのリストを比較する場合、operator!=() はポインタのアドレスを比較するため、obj1obj3 は内容が同じでもアドレスが異なるため ptrList1 != ptrList3true になります。 ポインタが指すオブジェクトの内容で比較したい場合は、ループを使って各要素のポインタをデリファレンスし、カスタム型の operator==() を使って比較する必要があります。この例のように、ヌルポインタのチェックも忘れずに行うことが重要です。



QList::operator!=() は、2つの QList が完全に同一ではないことをシンプルに判定する便利な方法です。しかし、状況によっては、この演算子が提供する厳密な比較(要素数、内容、順序の全てが一致するか)では不十分な場合や、より柔軟な比較が必要な場合があります。

そのような場合に利用できる代替方法をいくつか紹介します。

QList::operator==() の反転

これは最も直接的な代替方法であり、事実上 operator!=() が内部で行っていることです。 list1 != list2!(list1 == list2) と同等です。

いつ使うか:

  • operator==() を使って明示的に「等しい」ことを確認し、その逆を条件としたい場合に使うことがあります。
  • 意味的には同じなので、コードの可読性や個人の好みに応じて選ぶことができます。


#include <QList>
#include <QDebug>

int main() {
    QList<int> list1 = {1, 2, 3};
    QList<int> list2 = {1, 2, 4}; // 異なる

    if (!(list1 == list2)) { // operator!=() と同じ結果
        qDebug() << "list1 と list2 は等しくありません (operator== の反転)。";
    } else {
        qDebug() << "list1 と list2 は等しいです (operator== の反転)。";
    }
    return 0;
}

要素の集合としての比較 (QSet を使用)

リストの要素の順序を無視して、両方のリストに含まれる要素の「集合」が同じかどうかを比較したい場合、QSet を利用するのが最も効率的で Qt らしい方法です。

いつ使うか:

  • 重複する要素がある場合、QSet は重複を排除するため、その点も考慮に入れる必要があります。
  • リストの要素の順序は関係なく、単に同じ要素がすべて含まれているかどうかを確認したい場合。


#include <QList>
#include <QSet> // QSet を使用するために必要
#include <QDebug>

int main() {
    qDebug() << "--- QSet を使用した集合比較 ---";

    QList<int> listA = {1, 2, 3};
    QList<int> listB = {3, 1, 2}; // 順序は異なるが、要素は同じ
    QList<int> listC = {1, 2, 4}; // 要素が異なる
    QList<int> listD = {1, 2, 2, 3}; // 重複があるが、要素の種類は同じ

    QSet<int> setA = listA.toSet();
    QSet<int> setB = listB.toSet();
    QSet<int> setC = listC.toSet();
    QSet<int> setD = listD.toSet();

    if (setA != setB) { // QSet::operator!=() も順序を無視する
        qDebug() << "setA と setB は等しくありません。(実際は要素の集合は等しい)";
    } else {
        qDebug() << "setA と setB は等しいです。(順序を無視して要素の集合が同じ)"; // この行が出力される
    }

    if (setA != setC) {
        qDebug() << "setA と setC は等しくありません。(要素の集合が異なる)"; // この行が出力される
    } else {
        qDebug() << "setA と setC は等しいです。";
    }

    if (setA != setD) {
        qDebug() << "setA と setD は等しくありません。(実際は要素の集合は等しい)";
    } else {
        qDebug() << "setA と setD は等しいです。(QSetは重複を無視するため)"; // この行が出力される
    }

    return 0;
}

注意点

  • 重複する要素がある場合、QSet に変換するとそれらが失われるため、元のリストの重複の有無は比較に含まれません。
  • QSet はハッシュ可能な型(int, QString, QByteArray など)にのみ使用できます。カスタム型をQSetに格納するには、qHash()オーバーロードまたは特殊化が必要です。

手動での比較 (ループ、アルゴリズムの利用)

より複雑な比較ロジックや、特定の条件(例:ポインタの指す内容の比較、特定のプロパティのみを比較、部分的な一致)でリストを比較したい場合は、手動でループを回したり、C++標準ライブラリのアルゴリズム(std::equal, std::mismatch など)を利用したりします。

いつ使うか:

  • 一部の要素だけが異なれば「等しくない」としたいが、その「異なる」の定義がデフォルトと異なる場合。
  • 特定の条件に基づいて要素を比較したい場合。
  • ポインタのリストで、ポインタのアドレスではなく指し示すオブジェクトの内容で比較したい場合。
  • QList::operator!=()QSet の比較ロジックでは不十分な場合。
#include <QList>
#include <QString>
#include <QDebug>
#include <algorithm> // std::equal を使用

// (DataObject クラスと operator==, operator<< の定義は省略 - 例3を参照)
class DataObject {
public:
    int value;
    QString label;
    DataObject(int v = 0, const QString& l = "") : value(v), label(l) {}
    bool operator==(const DataObject& other) const {
        return (this->value == other.value && this->label == other.label);
    }
};
QDebug operator<<(QDebug debug, const DataObject& obj) {
    QDebugStateSaver saver(debug);
    debug.nospace() << "DataObject(value=" << obj.value << ", label='" << obj.label << "')";
    return debug;
}

int main() {
    qDebug() << "--- 手動での比較: ポインタの内容 ---";

    DataObject* obj1 = new DataObject(1, "Apple");
    DataObject* obj2 = new DataObject(2, "Banana");
    DataObject* obj3 = new DataObject(1, "Apple"); // obj1 と内容は同じだが、別アドレス

    QList<DataObject*> listA;
    listA << obj1 << obj2;

    QList<DataObject*> listB;
    listB << obj3 << obj2; // 最初の要素のアドレスが異なるが、内容は同じ

    bool areContentNotEqual = false;

    if (listA.size() != listB.size()) {
        areContentNotEqual = true;
    } else {
        // std::equal を使用して、ラムダ式で内容を比較
        // Qt 6以降では、QList::const_iterator はランダムアクセス可能
        areContentNotEqual = !std::equal(listA.begin(), listA.end(), listB.begin(),
                                         [](const DataObject* p1, const DataObject* p2) {
                                             if (p1 == nullptr && p2 == nullptr) return true;
                                             if (p1 == nullptr || p2 == nullptr) return false;
                                             return *p1 == *p2; // DataObject::operator== を使用
                                         });
    }

    if (areContentNotEqual) {
        qDebug() << "listA と listB は、内容的には等しくありません。";
    } else {
        qDebug() << "listA と listB は、内容的には等しいです。"; // この行が出力される
    }

    // メモリの解放
    delete obj1;
    delete obj2;
    delete obj3;
    return 0;
}

解説
std::equal を使用し、カスタムの比較述語(ラムダ式)を渡すことで、ポインタが指すオブジェクトの内容に基づいて比較を行っています。ヌルポインタの扱いもここで定義できます。

例3.2: 部分的な一致、または特定の条件での不一致の検出

例えば、リストの長さが同じで、最初の要素が異なる場合にのみ「等しくない」と判断したい、といったニッチなケース。

#include <QList>
#include <QDebug>

int main() {
    qDebug() << "--- 手動での比較: 特定の条件での不一致 ---";

    QList<int> listX = {10, 20, 30};
    QList<int> listY = {10, 20, 40}; // 3番目の要素が異なる
    QList<int> listZ = {5, 20, 30};  // 1番目の要素が異なる
    QList<int> listW = {10, 20};     // 長さが異なる

    bool customNotEqual = false;

    // 条件: 長さが同じで、かつ最初の要素が異なる場合に「等しくない」と判断
    if (listX.size() == listZ.size() && !listX.isEmpty() && !listZ.isEmpty()) {
        if (listX.first() != listZ.first()) {
            customNotEqual = true;
        }
    }
    // 長さが異なる場合も「等しくない」としたいなら追加
    if (listX.size() != listZ.size()) {
        customNotEqual = true;
    }


    if (customNotEqual) {
        qDebug() << "listX と listZ は、カスタム条件で等しくありません。"; // この行が出力される
    } else {
        qDebug() << "listX と listZ は、カスタム条件で等しいです。";
    }

    // listX と listY はこの条件では等しくないと判断されない (最初の要素は同じなので)
    customNotEqual = false;
    if (listX.size() == listY.size() && !listX.isEmpty() && !listY.isEmpty()) {
        if (listX.first() != listY.first()) {
            customNotEqual = true;
        }
    }
    if (customNotEqual) {
        qDebug() << "listX と listY は、カスタム条件で等しくありません。";
    } else {
        qDebug() << "listX と listY は、カスタム条件で等しいです。"; // この行が出力される
    }

    return 0;
}

解説
このように、QList::operator!=() が提供するデフォルトの比較ロジックでは対応できないような、より細かな条件でリストの不一致を判断したい場合は、プログラマが直接比較ロジックを記述する必要があります。

QList::operator!=() は最もシンプルで、リストの厳密な不一致を判定するのに適しています。しかし、用途によっては以下の代替手段を検討すると良いでしょう。

  • 手動ループや標準アルゴリズム (std::equal など) + ラムダ式: ポインタの内容比較、特定のプロパティのみの比較、部分的な一致など、複雑な比較ロジックが必要な場合。
  • QSet を使用: 順序を無視して、要素の集合として比較したい場合。ただし、重複の扱いやハッシュ可能であることの制約に注意。
  • !(list1 == list2): 意味的に同じ。