QList::contains()の落とし穴: よくあるエラーと解決策

2025-06-06

template <typename AT> bool QList::contains(const AT &value) const とは

この関数は、Qtの汎用コンテナクラスであるQListが提供するメンバー関数の一つです。QListは、リスト形式で要素を格納するためのクラスで、C++のstd::vectorstd::listに似た機能を提供します。

テンプレートの<typename AT>という部分は、このcontains関数がジェネリック(汎用的)であることを示しています。

  • const: 関数のシグネチャの末尾にあるconstは、このcontains関数が呼び出されたQListオブジェクト自体を一切変更しないことを示します。つまり、この関数は「読み取り専用」の操作を実行します。

  • (const AT &value): 関数の引数です。

    • const AT &: 検索したい値の参照をconst付きで受け取ります。constは、関数内でこのvalueが変更されないことを保証します。&は参照渡しであり、値のコピーを避けることでパフォーマンスを向上させます。ATは前述の型パラメータです。
    • value: リスト内に存在するかどうかを確認したい具体的な値です。
  • QList::contains: QListクラスのcontainsという名前のメンバー関数であることを示します。

  • bool: この関数の戻り値の型です。指定された値がリスト内に存在すればtrueを、存在しなければfalseを返します。

  • template <typename AT>: これはC++のテンプレート構文です。ATは型パラメータであり、contains関数が呼び出される際に、その引数valueの型が何であるかによって自動的に決定されます。これにより、QListに格納されている要素の型Tとは異なる型の値を検索できる柔軟性を提供します。ただし、通常はQList<T>::contains(const T &value)のように、QListの要素型Tと同じ型の値を検索するために使用されます。

動作

QList::contains(value)は、リストの先頭から順に各要素とvalueを比較し、valueと等しい要素が見つかれば即座にtrueを返します。リストの最後まで検索してもvalueと等しい要素が見つからなかった場合はfalseを返します。

重要な注意点
QList::contains()が要素の存在をチェックするためには、比較対象となる要素の型がoperator== (等価比較演算子) を実装している必要があります。つまり、QListに格納されている要素の型Tと、containsに渡されるvalueの型ATの間で比較が可能である必要があります。カスタムクラスをQListに格納してcontains()を使用する場合、そのカスタムクラスにoperator==を適切に定義しておく必要があります。

#include <QList>
#include <QString>
#include <QDebug> // qDebug() のために必要

int main() {
    QList<QString> fruits;
    fruits << "Apple" << "Banana" << "Orange" << "Grape";

    // "Banana" がリストに含まれているか確認
    if (fruits.contains("Banana")) {
        qDebug() << "Banana is in the list."; // 出力: Banana is in the list.
    } else {
        qDebug() << "Banana is not in the list.";
    }

    // "Kiwi" がリストに含まれているか確認
    if (fruits.contains("Kiwi")) {
        qDebug() << "Kiwi is in the list.";
    } else {
        qDebug() << "Kiwi is not in the list."; // 出力: Kiwi is not in the list.
    }

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

    // 20 がリストに含まれているか確認
    if (numbers.contains(20)) {
        qDebug() << "20 is in the list."; // 出力: 20 is in the list.
    }

    return 0;
}


operator== の未実装または不適切な実装

エラーの症状

  • カスタムクラスや構造体をQListに格納している場合に発生しやすい。
  • QList<MyClass>::contains() が常に false を返す、あるいは正しく動作しない。
  • コンパイルエラー: error: invalid conversion from 'const T' to 'T&' (または類似のメッセージ)

原因
QList::contains()は内部的にoperator==(等価比較演算子)を使用して、リスト内の要素と検索対象の値を比較します。カスタムクラスや構造体をQListに格納する場合、その型に対してoperator==を適切にオーバーロードしていないと、コンパイルエラーになったり、意図しない比較結果(例えば、異なるオブジェクトでもメモリ上のアドレスが同じならtrueになってしまうなど)になったりします。

トラブルシューティング
QListに格納している型(T)と、containsに渡す値の型(AT)の両方に対して、const参照を引数に取り、const修飾されたoperator== を定義する必要があります。


// MyClass.h
class MyClass {
public:
    int id;
    QString name;

    MyClass(int id, const QString& name) : id(id), name(name) {}

    // 適切な operator== の実装
    // QList::contains() が内部で const T& を引数として呼び出すため、const 修飾が必須
    bool operator==(const MyClass& other) const {
        return (id == other.id && name == other.name);
    }
};

// main.cpp
#include <QList>
#include <QDebug>
#include "MyClass.h" // MyClass の定義をインクルード

int main() {
    QList<MyClass> myList;
    myList.append(MyClass(1, "Alice"));
    myList.append(MyClass(2, "Bob"));

    // 正しく動作する例
    if (myList.contains(MyClass(1, "Alice"))) {
        qDebug() << "Alice (ID 1) found.";
    }

    // 存在しない要素の検索
    if (!myList.contains(MyClass(3, "Charlie"))) {
        qDebug() << "Charlie (ID 3) not found.";
    }

    return 0;
}

ポインタを格納している場合(QList<MyClass*>)
QList<MyClass*>のようにポインタを格納している場合、デフォルトのoperator==はポインタのアドレス比較を行います。つまり、たとえオブジェクトの内容が同じでも、異なるアドレスにある場合はfalseを返します。オブジェクトの内容で比較したい場合は、ポインタの比較を行うフリー関数としてのoperator==を定義するか、std::find_ifとラムダ式を使用します。

// main.cpp
#include <QList>
#include <QDebug>
#include <algorithm> // std::find_if のために必要

class MyClass {
public:
    int id;
    QString name;

    MyClass(int id, const QString& name) : id(id), name(name) {}

    // オブジェクトの等価比較演算子
    bool operator==(const MyClass& other) const {
        return (id == other.id && name == other.name);
    }
};

// ポインタの比較を行うフリー関数 (MyClass* の contains でオブジェクトの内容を比較したい場合)
// ただし、QList::contains() が自動的にこれを呼び出すわけではない点に注意
// QList<MyClass*>::contains() はポインタのアドレスを比較する
/*
bool operator==(const MyClass* lhs, const MyClass* rhs) {
    if (!lhs || !rhs) return lhs == rhs; // nullptr のハンドリング
    return *lhs == *rhs; // オブジェクトの内容を比較
}
*/

int main() {
    QList<MyClass*> myList;
    myList.append(new MyClass(1, "Alice"));
    myList.append(new MyClass(2, "Bob"));

    MyClass* searchTarget = new MyClass(1, "Alice");

    // NG: この contains はポインタのアドレスを比較するため、false を返す可能性が高い
    // (searchTarget はリストに追加されたものとは異なるアドレスにあるため)
    if (myList.contains(searchTarget)) {
        qDebug() << "Alice (ID 1) pointer found (this might be wrong).";
    } else {
        qDebug() << "Alice (ID 1) pointer not found (as expected, different address).";
    }

    // OK: オブジェクトの内容で比較したい場合は std::find_if を使う
    auto it = std::find_if(myList.constBegin(), myList.constEnd(),
                           [searchTarget](const MyClass* item) {
                               return item && (*item == *searchTarget);
                           });

    if (it != myList.constEnd()) {
        qDebug() << "Alice (ID 1) object content found using std::find_if.";
    } else {
        qDebug() << "Alice (ID 1) object content not found using std::find_if.";
    }

    // メモリリークを防ぐために、動的に確保したオブジェクトを解放
    qDeleteAll(myList);
    delete searchTarget; // 検索用に作ったオブジェクトも解放

    return 0;
}

QList<MyClass*>の場合にcontains()を使用すると、MyClassoperator==が呼び出されるのではなく、MyClass*のアドレス比較が行われます。これはC++のポインタの挙動です。そのため、異なるアドレスに存在するが内容が同じオブジェクトを検索したい場合は、std::find_ifを使用するのが一般的です。

const 修飾子に関する問題

エラーの症状

  • QListconstな文脈で使われているが、contains()に渡す値の型に対するoperator==constでない場合に発生。
  • コンパイルエラー: error: passing 'const MyClass' as 'this' argument discards qualifiers [-fpermissive] (特にQt 6でこのエラーがより厳格になりました)

原因
QList::contains()関数自体がconstメンバー関数として宣言されています。これは、この関数がQListオブジェクトの状態を変更しないことを意味します。そのため、contains()が内部で呼び出す要素の比較演算子(operator==)も、比較対象のオブジェクトをconstとして扱う必要があります。つまり、operator==const修飾されている必要があります。

トラブルシューティング
カスタムクラスのoperator==を定義する際に、必ず関数の最後にconstキーワードを付けます。

class MyClass {
public:
    int value;
    // ...

    // 正しい operator== の定義
    bool operator==(const MyClass& other) const { // ここに const を追加
        return value == other.value;
    }
};

意図しない型変換(typename AT の利用)

エラーの症状

  • 意図しない比較結果(例えば、intのリストなのにdoubleを渡してしまい、予期せぬ結果になるなど)
  • コンパイルエラー(型不一致)

原因
containstemplate <typename AT>となっているため、柔軟な型を引数として受け入れますが、これにより意図しない型変換が発生し、結果として比較が正しく行われない可能性があります。例えば、QList<int>doubleを渡した場合、doubleintに丸められて比較されるため、期待通りの結果にならないことがあります。

トラブルシューティング

  • 型の一貫性を保つ
    可能な限り、QListに格納されている要素と同じ型の値をcontains()に渡すようにします。
  • 明示的な型キャスト
    比較したい値がQListの要素型と異なる場合は、明示的に型をキャストして渡します。
    QList<int> numbers;
    numbers << 10 << 20 << 30;
    
    // double を int にキャストして比較
    if (numbers.contains(static_cast<int>(20.5))) {
        qDebug() << "Contains 20 (after casting)."; // numbers に 20 が含まれていれば true
    }
    

QObjectを継承したクラスのインスタンスを値として格納した場合

エラーの症状

  • QList<MyQObjectDerivedClass> のような宣言ができない。
  • コンパイルエラー: error: 'QObject' is an abstract class (あるいは類似のメッセージ)

原因
QObjectを継承したクラスは、コピーコンストラクタと代入演算子が削除(deleted)されているため、QListのような値セマンティクスを持つコンテナに直接格納できません。QListは要素をコピーして保持しようとするため、この制約に違反します。

トラブルシューティング
QObjectを継承したクラスをQListに格納する場合は、ポインタ(QObject*またはQSharedPointer<QObject>など)で格納する必要があります。


#include <QList>
#include <QObject>
#include <QDebug>
#include <QSharedPointer> // QSharedPointer を使う場合

class MyCustomObject : public QObject {
    Q_OBJECT
public:
    int id;
    MyCustomObject(int id, QObject* parent = nullptr) : QObject(parent), id(id) {}

    // QObject を継承しているため、MyCustomObject の operator== は通常定義しない
    // ポインタの contains() はアドレス比較になる
};

// MyCustomObject の内容を比較するフリー関数 (QList<MyCustomObject*> で使用する場合)
// これを定義しても contains はアドレス比較になる
/*
bool operator==(const MyCustomObject& obj1, const MyCustomObject& obj2) {
    return obj1.id == obj2.id;
}
*/

int main() {
    // NG: QObject を継承したクラスのインスタンスを直接格納しようとするとコンパイルエラー
    // QList<MyCustomObject> objectList;

    // OK: ポインタで格納する
    QList<MyCustomObject*> pointerList;
    pointerList.append(new MyCustomObject(1));
    pointerList.append(new MyCustomObject(2));

    MyCustomObject* searchPtr = new MyCustomObject(1);

    // QList<MyCustomObject*>::contains() はポインタのアドレスを比較する
    if (pointerList.contains(searchPtr)) {
        qDebug() << "Pointer search found (likely wrong if content is desired).";
    } else {
        qDebug() << "Pointer search not found (as expected).";
    }

    // オブジェクトの内容で検索したい場合は std::find_if を使用
    auto it_ptr = std::find_if(pointerList.constBegin(), pointerList.constEnd(),
                               [searchPtr](const MyCustomObject* obj) {
                                   return obj && obj->id == searchPtr->id;
                               });
    if (it_ptr != pointerList.constEnd()) {
        qDebug() << "Object content found in pointerList using std::find_if.";
    }

    // QSharedPointer を使うとメモリ管理が楽になる
    QList<QSharedPointer<MyCustomObject>> sharedPointerList;
    sharedPointerList.append(QSharedPointer<MyCustomObject>(new MyCustomObject(10)));
    sharedPointerList.append(QSharedPointer<MyCustomObject>(new MyCustomObject(20)));

    QSharedPointer<MyCustomObject> searchSharedPtr(new MyCustomObject(10));

    // QSharedPointer の contains は、QSharedPointer 自体の比較(ポインタが指すアドレス)を行う
    // あるいは、QSharedPointer が持つ operator== に依存する
    if (sharedPointerList.contains(searchSharedPtr)) {
         qDebug() << "Shared pointer search found (likely wrong if content is desired).";
    } else {
        qDebug() << "Shared pointer search not found (as expected, different QSharedPointer instance).";
    }

    // QSharedPointer でオブジェクトの内容を比較したい場合も std::find_if
    auto it_shared = std::find_if(sharedPointerList.constBegin(), sharedPointerList.constEnd(),
                                  [searchSharedPtr](const QSharedPointer<MyCustomObject>& obj) {
                                      return obj && searchSharedPtr && obj->id == searchSharedPtr->id;
                                  });
    if (it_shared != sharedPointerList.constEnd()) {
        qDebug() << "Object content found in sharedPointerList using std::find_if.";
    }


    // pointerList の動的に確保したオブジェクトを解放
    qDeleteAll(pointerList);
    delete searchPtr; // 検索用に作ったオブジェクトも解放

    // sharedPointerList のオブジェクトは QSharedPointer が自動的に解放してくれる
    return 0;
}

QList の内部データ構造によるパフォーマンス問題

エラーの症状

  • 大規模なリストでcontains()を頻繁に呼び出すと、アプリケーションの動作が遅くなる。

原因
QList::contains()は、要素の検索に線形探索(O(n))を行います。リストのサイズが大きくなればなるほど、検索にかかる時間は長くなります。

トラブルシューティング

  • リストの事前ソートとqBinaryFind
    • リストがソートされている場合、qBinaryFind関数(二分探索)を使用してO(log n)で要素を検索できます。ただし、リストをソート状態に保つためのコストがかかります。
  • QSetの使用を検討
    • 重複を許さず、要素の存在チェックのみを高速に行いたい場合は、QSetが適しています。こちらもcontains()は通常O(1)です。
  • QHashまたはQMapの使用を検討
    • キーによって要素を迅速に検索する必要がある場合は、QHash(ハッシュテーブル)またはQMap(ソートされたツリー)を使用することを検討します。これらのコンテナのcontains()は、通常O(1)またはO(log n)のパフォーマンスを提供します。
    • 検索キーがユニークである場合に特に有効です。
#include <QHash>
#include <QString>
#include <QDebug>

int main() {
    QHash<int, QString> employeeIdToName;
    employeeIdToName.insert(101, "Alice");
    employeeIdToToName.insert(102, "Bob");
    employeeIdToToName.insert(103, "Charlie");

    // ID 102 が存在するか確認
    if (employeeIdToName.contains(102)) {
        qDebug() << "Employee ID 102 exists: " << employeeIdToName.value(102); // 出力: Employee ID 102 exists: Bob
    }

    // ID 104 が存在するか確認
    if (!employeeIdToName.contains(104)) {
        qDebug() << "Employee ID 104 does not exist."; // 出力: Employee ID 104 does not exist.
    }

    return 0;
}


基本的なデータ型(int, QString など)の場合

最も一般的な使用例です。Qtの組み込み型や標準のC++型は、operator== が適切に定義されているため、そのまま contains() を使用できます。

#include <QList>
#include <QString>
#include <QDebug> // qDebug() のために必要

int main() {
    // int 型の QList
    QList<int> intList;
    intList << 10 << 20 << 30 << 40 << 50;

    // 20 が含まれているか?
    if (intList.contains(20)) {
        qDebug() << "intList に 20 が含まれています。"; // 出力: intList に 20 が含まれています。
    } else {
        qDebug() << "intList に 20 は含まれていません。";
    }

    // 100 が含まれているか?
    if (intList.contains(100)) {
        qDebug() << "intList に 100 が含まれています。";
    } else {
        qDebug() << "intList に 100 は含まれていません。"; // 出力: intList に 100 は含まれていません。
    }

    qDebug() << "--------------------";

    // QString 型の QList
    QList<QString> stringList;
    stringList << "Apple" << "Banana" << "Orange";

    // "Banana" が含まれているか?
    if (stringList.contains("Banana")) {
        qDebug() << "stringList に Banana が含まれています。"; // 出力: stringList に Banana が含まれています。
    } else {
        qDebug() << "stringList に Banana は含まれていません。";
    }

    // "Grape" が含まれているか?
    if (stringList.contains("Grape")) {
        qDebug() << "stringList に Grape が含まれています。";
    } else {
        qDebug() << "stringList に Grape は含まれていません。"; // 出力: stringList に Grape は含まれていません。
    }

    // 大文字・小文字を区別しない検索 (QStringList の場合)
    // QStringList は QList<QString> を継承しており、便利な関数を提供
    QStringList caseSensitiveList;
    caseSensitiveList << "apple" << "Banana";
    if (caseSensitiveList.contains("APPLE", Qt::CaseInsensitive)) {
        qDebug() << "caseSensitiveList に APPLE (大文字小文字無視) が含まれています。"; // 出力: caseSensitiveList に APPLE (大文字小文字無視) が含まれています。
    }

    return 0;
}

カスタムクラスの場合

カスタムクラスを QList に格納し、contains() を使用するには、そのクラスに等価比較演算子 operator== を定義する必要があります。この演算子が定義されていないと、コンパイルエラーになるか、意図しない結果(例えば、オブジェクトのアドレス比較など)になります。

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

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

    MyItem(int id, const QString& name) : id(id), name(name) {}

    // 重要: QList::contains() が使用する operator== を定義
    // const MyItem& other: 比較対象のアイテムを const 参照で受け取る
    // const: このメンバー関数が MyItem オブジェクトの状態を変更しないことを示す
    bool operator==(const MyItem& other) const {
        return (this->id == other.id && this->name == other.name);
    }
};

int main() {
    QList<MyItem> myItemsList;
    myItemsList.append(MyItem(1, "Laptop"));
    myItemsList.append(MyItem(2, "Mouse"));
    myItemsList.append(MyItem(3, "Keyboard"));

    // 存在するアイテムを検索
    MyItem searchItem1(2, "Mouse");
    if (myItemsList.contains(searchItem1)) {
        qDebug() << "myItemsList に ID 2 の Mouse が含まれています。"; // 出力: myItemsList に ID 2 の Mouse が含まれています。
    } else {
        qDebug() << "myItemsList に ID 2 の Mouse は含まれていません。";
    }

    // 存在しないアイテムを検索 (ID は同じだが名前が異なる)
    MyItem searchItem2(1, "Tablet");
    if (myItemsList.contains(searchItem2)) {
        qDebug() << "myItemsList に ID 1 の Tablet が含まれています。";
    } else {
        qDebug() << "myItemsList に ID 1 の Tablet は含まれていません。"; // 出力: myItemsList に ID 1 の Tablet は含まれていません。
    }

    // 存在しないアイテムを検索 (完全に異なる)
    MyItem searchItem3(4, "Monitor");
    if (myItemsList.contains(searchItem3)) {
        qDebug() << "myItemsList に ID 4 の Monitor が含まれています。";
    } else {
        qDebug() << "myItemsList に ID 4 の Monitor は含まれていません。"; // 出力: myItemsList に ID 4 の Monitor は含まれていません。
    }

    return 0;
}

ポインタを格納した QList の場合

QList<MyItem*> のようにポインタを格納する場合、contains()ポインタのアドレス自体を比較します。オブジェクトの内容を比較したい場合は、通常 std::find_if を使用します。

#include <QList>
#include <QString>
#include <QDebug>
#include <algorithm> // std::find_if のために必要

class MyPointerItem {
public:
    int value;
    QString description;

    MyPointerItem(int v, const QString& d) : value(v), description(d) {}

    // この operator== は、MyPointerItem オブジェクトの内容を比較するためのもの
    // QList<MyPointerItem*>::contains() では直接使われない点に注意
    bool operator==(const MyPointerItem& other) const {
        return (this->value == other.value && this->description == other.description);
    }
};

int main() {
    QList<MyPointerItem*> pointerList;
    pointerList.append(new MyPointerItem(10, "First"));
    pointerList.append(new MyPointerItem(20, "Second"));
    pointerList.append(new MyPointerItem(30, "Third"));

    // 例 1: リストに実際に存在するポインタを検索
    // これはアドレス比較であり、MyPointerItem の operator== は使われない
    MyPointerItem* existingPtr = pointerList.at(1); // 20, "Second" を指すポインタ
    if (pointerList.contains(existingPtr)) {
        qDebug() << "pointerList に既存のポインタが含まれています (アドレス比較)。"; // 出力
    }

    qDebug() << "--------------------";

    // 例 2: 同じ内容だが異なるアドレスにあるオブジェクトを検索
    // contains() では False になる(アドレスが異なるため)
    MyPointerItem* searchTargetContent = new MyPointerItem(20, "Second");
    if (pointerList.contains(searchTargetContent)) {
        qDebug() << "pointerList に同じ内容のオブジェクトが含まれています (contains() はアドレス比較なので、通常ここには来ない)。";
    } else {
        qDebug() << "pointerList に同じ内容のオブジェクトは含まれていません (アドレスが異なるため)。"; // 出力
    }

    qDebug() << "--------------------";

    // 例 3: オブジェクトの内容で検索したい場合 (推奨される方法: std::find_if)
    auto it = std::find_if(pointerList.constBegin(), pointerList.constEnd(),
                           [searchTargetContent](const MyPointerItem* item) {
                               // item が nullptr でないことを確認し、オブジェクトの内容を比較
                               return item && (*item == *searchTargetContent);
                           });

    if (it != pointerList.constEnd()) {
        qDebug() << "std::find_if を使用して、pointerList に ID " << (*it)->value << " のオブジェクトが見つかりました。"; // 出力
    } else {
        qDebug() << "std::find_if を使用しても、pointerList に一致するオブジェクトは見つかりませんでした。";
    }

    // メモリリークを防ぐため、動的に確保したオブジェクトを解放する
    qDeleteAll(pointerList); // QList<T*> の要素を解放するQtのヘルパー関数
    delete searchTargetContent; // 検索用に作成したオブジェクトも解放

    return 0;
}

QObject 派生クラスの場合(QSharedPointer を使用)

QObject を継承するクラスはコピーできない(コピーコンストラクタと代入演算子が削除されている)ため、QList<MyQObject> のように直接格納することはできません。代わりにポインタ、特にスマートポインタ(QSharedPointer)を使用するのが一般的です。

QSharedPointercontains() は、その内部で管理しているポインタのアドレスを比較します。オブジェクトの内容を比較したい場合は、やはり std::find_if を使用します。

#include <QList>
#include <QObject>
#include <QString>
#include <QDebug>
#include <QSharedPointer> // QSharedPointer のために必要
#include <algorithm>      // std::find_if のために必要

class MyQObjectItem : public QObject {
    Q_OBJECT // Q_OBJECT マクロは QObject を継承するクラスに必須
public:
    int uniqueId;
    QString name;

    MyQObjectItem(int id, const QString& n, QObject* parent = nullptr)
        : QObject(parent), uniqueId(id), name(n) {}

    // QObject 派生クラスでは operator== を直接定義しないのが一般的。
    // 必要なら、外部関数やラムダ式で比較ロジックを提供する。
    // 例えば、デバッグや特定の目的のために定義する場合もあるが、QList::contains では使われない。
    /*
    bool operator==(const MyQObjectItem& other) const {
        return (this->uniqueId == other.uniqueId && this->name == other.name);
    }
    */
};

int main() {
    QList<QSharedPointer<MyQObjectItem>> sharedPointerList;
    sharedPointerList.append(QSharedPointer<MyQObjectItem>(new MyQObjectItem(101, "ServerA")));
    sharedPointerList.append(QSharedPointer<MyQObjectItem>(new MyQObjectItem(102, "ServerB")));
    sharedPointerList.append(QSharedPointer<MyQObjectItem>(new MyQObjectItem(103, "ServerC")));

    // 例 1: リスト内の既存の QSharedPointer を検索 (アドレス比較)
    QSharedPointer<MyQObjectItem> existingSharedPtr = sharedPointerList.at(0); // ServerA を指す
    if (sharedPointerList.contains(existingSharedPtr)) {
        qDebug() << "sharedPointerList に既存の QSharedPointer が含まれています (アドレス比較)。"; // 出力
    } else {
        qDebug() << "含まれていません。";
    }

    qDebug() << "--------------------";

    // 例 2: 同じ内容だが異なる QSharedPointer インスタンスを検索
    // contains() は通常 false を返す(QSharedPointer 自体のアドレスが異なるため)
    QSharedPointer<MyQObjectItem> searchTargetContent(new MyQObjectItem(102, "ServerB"));
    if (sharedPointerList.contains(searchTargetContent)) {
        qDebug() << "sharedPointerList に同じ内容のオブジェクトが含まれています (contains() は QSharedPointer のインスタンス比較なので、通常ここには来ない)。";
    } else {
        qDebug() << "sharedPointerList に同じ内容のオブジェクトは含まれていません (QSharedPointer のインスタンスが異なるため)。"; // 出力
    }

    qDebug() << "--------------------";

    // 例 3: QObject 派生クラスの**内容**で検索したい場合 (推奨される方法: std::find_if)
    auto it = std::find_if(sharedPointerList.constBegin(), sharedPointerList.constEnd(),
                           [searchTargetContent](const QSharedPointer<MyQObjectItem>& item) {
                               // nullptr チェックを行い、オブジェクトの内容を比較
                               return item && searchTargetContent && (item->uniqueId == searchTargetContent->uniqueId && item->name == searchTargetContent->name);
                           });

    if (it != sharedPointerList.constEnd()) {
        qDebug() << "std::find_if を使用して、sharedPointerList に ID " << (*it)->uniqueId << " のオブジェクトが見つかりました。"; // 出力
    } else {
        qDebug() << "std::find_if を使用しても、sharedPointerList に一致するオブジェクトは見つかりませんでした。";
    }

    // QSharedPointer を使用しているため、スコープを抜けると自動的にメモリが解放されます。
    // searchTargetContent も自動的に解放されます。
    return 0;
}


リストが非常に大きい場合や、頻繁に存在チェックを行う必要がある場合、QList::contains() はパフォーマンスのボトルネックになる可能性があります。このような場合に考慮すべき代替方法をいくつか説明します。

QList::indexOf() または QList::lastIndexOf() を使用する

contains() と同様に線形探索を行いますが、要素が見つかった場合のインデックスを返します。contains() の内部でもこれらが使用されています。

  • lastIndexOf(const AT &value, qsizetype from = -1) const: リストの末尾から指定した値の最後の出現位置のインデックスを返します。見つからない場合は -1 を返します。
  • indexOf(const AT &value, qsizetype from = 0) const: リストの先頭から指定した値の最初の出現位置のインデックスを返します。見つからない場合は -1 を返します。