QList::append()の落とし穴?Qtでのリスト操作エラーと解決策
QtプログラミングにおけるQList::append()
は、QList
というコンテナクラスの非常に基本的な関数で、リストの末尾に要素を追加するために使用されます。
QListとは?
まず、QList
について簡単に触れておきます。QList
はQtフレームワークが提供するジェネリックなコンテナクラスの一つで、C++のstd::vector
やstd::list
のような、要素のリストを格納するためのものです。
- 高速な挿入/削除
リストの先頭や末尾への要素の追加・削除は非常に高速です(ほとんどの場合、定数時間O(1))。これは、QList
が内部的に両端に余分なメモリを事前に割り当てているためです。 - インデックスアクセス
[]
演算子などを使って、インデックス(添字)で要素にアクセスできます。 - 動的な配列
必要に応じてサイズが自動的に拡張・縮小されます。
QList::append()
は、その名の通り、QList
の末尾に新しい要素を追加するためのメンバ関数です。
書式
void QList::append(const T &value)
value
: リストの末尾に追加したい要素です。T
:QList
が格納する要素の型です(例:int
,QString
,MyCustomClass
など)。
動作
append()
が呼び出されると、指定されたvalue
がQList
の現在の最後の要素の次に追加され、リストのサイズが1つ増えます。
例
#include <QCoreApplication>
#include <QList>
#include <QDebug> // qWarning() や qDebug() を使うために必要
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
// int型のQListを作成
QList<int> numbers;
// append()を使って要素を追加
numbers.append(10);
numbers.append(20);
numbers.append(30);
qDebug() << "リストの現在の要素:";
for (int num : numbers) {
qDebug() << num;
}
// 出力例:
// リストの現在の要素:
// 10
// 20
// 30
// さらに要素を追加
numbers.append(40);
qDebug() << "要素追加後のリスト:";
for (int num : numbers) {
qDebug() << num;
}
// 出力例:
// 要素追加後のリスト:
// 10
// 20
// 30
// 40
return a.exec();
}
この例では、numbers
というQList<int>
を作成し、append()
を使って順に10、20、30、40という整数を追加しています。追加されるたびに、要素はリストの末尾に配置されます。
他の追加方法との比較
QList
には、append()
の他にも要素を追加する方法がいくつかあります。
-
insert(int i, const T &value)
指定されたインデックスi
に要素を挿入します。既存の要素は後ろにずれます。append()
は、実質的にinsert(size(), value)
と同じ動作をします。 -
push_back()
これもappend()
と全く同じ機能を提供します。どちらを使っても構いません。 -
operator<<() (ストリーム演算子)
append()
と同じように要素を末尾に追加します。複数の要素をチェーンして追加できるため、より簡潔なコードになります。QList<QString> list; list << "one" << "two" << "three"; // list: ["one", "two", "three"]
型の不一致 (Type Mismatch)
これは最もよくあるエラーの一つです。QList
は特定の型の要素を格納するように宣言されますが、append()
しようとしている要素の型がその型と一致しない場合に発生します。
エラーの例
QList<int> intList;
intList.append("hello"); // コンパイルエラー: QStringをintListに追加できない
トラブルシューティング
- QListの宣言の確認
そもそもQList
の宣言が意図した型になっているかを確認します。 - 型キャスト
もし、追加したい要素が互換性のある型であれば、明示的にキャストすることで解決できる場合があります。しかし、データ損失や意味的に不適切なキャストは避けるべきです。QList<double> doubleList; int intValue = 10; doubleList.append(static_cast<double>(intValue)); // OK
- コンパイルエラーの確認
コンパイラは通常、no matching function for call to 'QList<int>::append(const char [6])'
のようなエラーメッセージを出します。このメッセージで、期待される型(この場合はint
)と渡された型(この場合はconst char*
)の不一致がわかります。
ポインタの取り扱い (Handling Pointers)
QList
は値型(value type)を扱うのが得意ですが、ポインタを格納する場合、メモリ管理に注意が必要です。append()
自体がエラーを引き起こすわけではありませんが、追加したポインタの指すオブジェクトのライフタイム管理を怠ると問題が発生します。
問題の例
QList<MyObject*> objectPointers;
for (int i = 0; i < 5; ++i) {
MyObject *obj = new MyObject(); // ヒープにオブジェクトを生成
// objの設定...
objectPointers.append(obj);
}
// この後、objectPointersに追加されたMyObject*のメモリを解放しないとメモリリーク
トラブルシューティング
- スマートポインタの利用
C++11以降のスマートポインタ(std::shared_ptr
,std::unique_ptr
など)を使用すると、メモリ管理を自動化できます。Qt 5以降ではQSharedPointer
やQScopedPointer
も利用できます。QList<QSharedPointer<MyObject>> sharedObjectList; for (int i = 0; i < 5; ++i) { sharedObjectList.append(QSharedPointer<MyObject>(new MyObject())); // 自動でメモリ管理 } // sharedObjectList がスコープを抜けるときに MyObject は自動的に解放される
- メモリ解放
QList
がポインタの所有権を持つ場合、QList
が破棄される際や、リストから要素が削除される際に、明示的にdelete
を行う必要があります。// MyObject* を削除する関数やループ qDeleteAll(objectPointers); // Qtの便利な関数。リスト内のポインタを全てdeleteする objectPointers.clear(); // リストをクリア
- 所有権の明確化
QList
がポインタの所有権を持つのか、それとも単にポインタを保持するだけなのかを明確にします。
大量の要素追加によるパフォーマンス問題 (Performance Issues with Large Additions)
QList::append()
は通常高速(償却定数時間)ですが、非常に大量の要素をループで追加する際や、リストの初期サイズが非常に小さい場合に、頻繁なメモリ再割り当てが発生し、パフォーマンスが低下する可能性があります。
問題の例
QList<int> largeList;
for (int i = 0; i < 1000000; ++i) {
largeList.append(i); // 頻繁な再割り当てが発生する可能性
}
トラブルシューティング
- QVectorの検討
大量の要素を格納し、頻繁な挿入/削除がない場合は、よりメモリ効率の良いQVector
を検討することも有効です。QVector
はQList
よりも連続したメモリ配置を保証するため、インデックスアクセスがより高速になる傾向があります。 - reserve()の利用
あらかじめリストに十分な容量を予約することで、不要なメモリ再割り当てを減らし、パフォーマンスを向上させることができます。QList<int> largeList; largeList.reserve(1000000); // 必要な容量を事前に確保 for (int i = 0; i < 1000000; ++i) { largeList.append(i); }
コピーコンストラクタや代入演算子の問題 (Issues with Copy Constructor/Assignment Operator)
QList::append()
は、追加する要素のコピーを作成します(値渡し)。もし、追加しようとしているカスタムクラスに適切なコピーコンストラクタや代入演算子がない場合、シャローコピー(浅いコピー)が行われ、予期せぬ動作やクラッシュの原因となることがあります。
問題の例
class MyData {
public:
int* data;
MyData(int val) { data = new int(val); }
~MyData() { delete data; }
// コピーコンストラクタと代入演算子が定義されていない場合
};
QList<MyData> dataList;
MyData d1(10);
dataList.append(d1); // d1のシャローコピーが作成される
MyData d2 = dataList.at(0); // これもシャローコピー
// d1がスコープを抜けてdataがdeleteされると、dataList内のコピーのdataポインタも不正になる (double freeの可能性)
トラブルシューティング
- スマートポインタの活用
上記2.で述べたように、カスタムクラスのポインタをQList
に格納する代わりにスマートポインタを利用することで、この問題も回避できます。 - [Qt] 暗黙的な共有 (Implicit Sharing) の活用
Qtの多くのクラス(QString
,QByteArray
,QImage
など)は「暗黙的な共有(Copy-on-Write)」という最適化を使用しており、コピーコストを最小限に抑えています。カスタムクラスでも同様のメカニズムを実装することで、パフォーマンスと安全性を両立できます。 - 適切なコピーコンストラクタと代入演算子の定義
カスタムクラスがポインタやリソースを管理している場合、ディープコピー(深いコピー)を行うように、コピーコンストラクタ、代入演算子、そしてデストラクタを適切に定義(いわゆる「Rule of Three/Five/Zero」)する必要があります。
スレッドセーフティ (Thread Safety)
複数のスレッドから同時に同じQList
に対してappend()
操作を行う場合、データ競合(data race)が発生し、未定義の動作やクラッシュにつながる可能性があります。
問題の例
QList<int> sharedList;
// 複数のスレッドが同時に sharedList.append(value); を呼び出す
- Qt Concurrentの利用
並列処理を行う必要がある場合、Qt Concurrentフレームワーク(QtConcurrent::map
,QtConcurrent::filter
,QtConcurrent::run
など)を検討します。これらはスレッドセーフな方法でコレクションを操作するための高レベルなAPIを提供します。 - ミューテックスの利用
QMutex
などの排他制御メカニズムを使用して、QList
へのアクセスを同期させます。QList<int> sharedList; QMutex mutex; // スレッドA: mutex.lock(); sharedList.append(someValueA); mutex.unlock(); // スレッドB: mutex.lock(); sharedList.append(someValueB); mutex.unlock();
QList::append()
は、QList
の末尾に要素を追加するための基本的な関数です。ここでは、様々なデータ型での使用例や、関連する便利な機能との組み合わせを説明します。
基本的な型 (int, QStringなど) の追加
最も一般的な使い方です。数値や文字列などをリストに追加します。
#include <QCoreApplication>
#include <QList>
#include <QString>
#include <QDebug> // デバッグ出力用
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
// 整数 (int) のリスト
QList<int> intList;
qDebug() << "--- intList ---";
intList.append(10); // 10 を追加
intList.append(20); // 20 を追加
intList.append(30); // 30 を追加
qDebug() << "intList size:" << intList.size(); // サイズを確認
qDebug() << "intList:" << intList; // リストの内容を出力 (Qt 5.10以降でQListの直接出力が可能)
// 文字列 (QString) のリスト
QList<QString> stringList;
qDebug() << "\n--- stringList ---";
stringList.append("Apple");
stringList.append("Banana");
stringList.append("Cherry");
qDebug() << "stringList size:" << stringList.size();
qDebug() << "stringList:" << stringList;
// 別の追加方法 (operator<<)
QList<double> doubleList;
qDebug() << "\n--- doubleList (operator<<) ---";
doubleList << 1.23 << 4.56 << 7.89; // << 演算子を使って複数の要素を連続で追加
qDebug() << "doubleList size:" << doubleList.size();
qDebug() << "doubleList:" << doubleList;
return a.exec();
}
出力例
--- intList ---
intList size: 3
intList: (10, 20, 30)
--- stringList ---
stringList size: 3
stringList: ("Apple", "Banana", "Cherry")
--- doubleList (operator<<) ---
doubleList size: 3
doubleList: (1.23, 4.56, 7.89)
解説
QDebug
を使ってQList
のオブジェクトを直接出力できるのはQt 5.10以降の機能です。それ以前のバージョンではループを使って要素を個別に表示する必要があります。operator<<
はappend()
のシンタックスシュガー(より簡潔な記述方法)であり、同じように末尾に追加します。複数の要素を一行で追加したい場合に便利です。append()
は、渡された値のコピーをリストの末尾に追加します。
カスタムクラス/構造体の追加
自分で定義したクラスや構造体のオブジェクトをQList
に追加することもできます。この場合、そのクラスがデフォルトコンストラクタ、コピーコンストラクタ、そして代入演算子を適切に持っている必要があります(「Rule of Three/Five/Zero」の原則)。Qtのコンテナは要素をコピーして格納するため、これらの特殊メンバ関数が重要になります。
#include <QCoreApplication>
#include <QList>
#include <QString>
#include <QDebug>
// カスタムデータ構造体
struct Person {
QString name;
int age;
// デフォルトコンストラクタ (QListが内部で必要とする場合がある)
Person() : age(0) {}
// コンストラクタ
Person(const QString &n, int a) : name(n), age(a) {}
// QDebugで出力するためのオーバーロード (オプションだが便利)
friend QDebug operator<<(QDebug debug, const Person &p) {
QDebugStateSaver saver(debug); // QDebugの状態を保存/復元
debug.nospace() << "Person(Name: " << p.name << ", Age: " << p.age << ")";
return debug;
}
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QList<Person> peopleList;
qDebug() << "--- peopleList ---";
// Personオブジェクトを直接作成して追加
peopleList.append(Person("Alice", 30));
peopleList.append(Person("Bob", 25));
// 別途作成したオブジェクトを追加
Person charlie("Charlie", 35);
peopleList.append(charlie);
qDebug() << "peopleList size:" << peopleList.size();
qDebug() << "peopleList:" << peopleList; // カスタムのoperator<<が呼ばれる
// リストの要素にアクセスして変更(リスト内のコピーを変更する点に注意)
if (!peopleList.isEmpty()) {
peopleList[0].age = 31; // リスト内のAliceの年齢を変更
qDebug() << "After modifying Alice's age:";
qDebug() << "peopleList:" << peopleList;
}
return a.exec();
}
出力例
--- peopleList ---
peopleList size: 3
peopleList: (Person(Name: "Alice", Age: 30), Person(Name: "Bob", Age: 25), Person(Name: "Charlie", Age: 35))
After modifying Alice's age:
peopleList: (Person(Name: "Alice", Age: 31), Person(Name: "Bob", Age: 25), Person(Name: "Charlie", Age: 35))
解説
operator<<
のオーバーロードは、QDebug
でPerson
オブジェクトを直接出力できるようにするためのものです。デバッグに非常に役立ちます。append()
は、Person
オブジェクトのコピーを作成してリストに追加します。そのため、Person
クラスに適切なコピーコンストラクタが必要です(多くの場合、デフォルトのコピーコンストラクタで十分ですが、ポインタを持つ場合は注意が必要です)。QList<Person>
のように宣言することで、Person
型のオブジェクトを格納できます。
ポインタのリスト (メモリ管理に注意)
QList
はポインタを格納することもできますが、その場合、ポインタが指すオブジェクトのメモリ管理(生成と解放)はプログラマの責任となります。
#include <QCoreApplication>
#include <QList>
#include <QString>
#include <QDebug>
class Animal {
public:
QString name;
Animal(const QString &n) : name(n) {
qDebug() << name << " created.";
}
~Animal() {
qDebug() << name << " destroyed.";
}
// QDebugで出力するためのオーバーロード (オプション)
friend QDebug operator<<(QDebug debug, const Animal *a) {
QDebugStateSaver saver(debug);
if (a) debug.nospace() << "Animal(Name: " << a->name << ")";
else debug.nospace() << "Animal(nullptr)";
return debug;
}
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QList<Animal*> animalPointers;
qDebug() << "--- animalPointers ---";
// ヒープにAnimalオブジェクトを生成し、そのポインタをリストに追加
animalPointers.append(new Animal("Dog"));
animalPointers.append(new Animal("Cat"));
animalPointers.append(new Animal("Bird"));
qDebug() << "animalPointers size:" << animalPointers.size();
qDebug() << "animalPointers:" << animalPointers; // ポインタのアドレスと内容が出力される
// リスト内のオブジェクトにアクセス
if (!animalPointers.isEmpty()) {
animalPointers.first()->name = "Golden Retriever"; // Dogの名前を変更
qDebug() << "After modifying first animal's name:";
qDebug() << "animalPointers:" << animalPointers;
}
// ★重要: ヒープに生成したオブジェクトのメモリを解放する
qDebug() << "\n--- Deleting animals ---";
// Qtが提供する便利な関数: リスト内のすべてのポインタをdeleteする
qDeleteAll(animalPointers);
animalPointers.clear(); // リスト自体もクリア
qDebug() << "animalPointers size after deletion and clear:" << animalPointers.size();
qDebug() << "animalPointers:" << animalPointers;
return a.exec();
}
出力例
--- animalPointers ---
Dog created.
Cat created.
Bird created.
animalPointers size: 3
animalPointers: (Animal(Name: "Dog"), Animal(Name: "Cat"), Animal(Name: "Bird"))
After modifying first animal's name:
animalPointers: (Animal(Name: "Golden Retriever"), Animal(Name: "Cat"), Animal(Name: "Bird"))
--- Deleting animals ---
Golden Retriever destroyed.
Cat destroyed.
Bird destroyed.
animalPointers size after deletion and clear: 0
animalPointers: ()
解説
- スマートポインタ(
QSharedPointer
やstd::unique_ptr
など)を使用すると、このような手動でのメモリ管理の手間を省くことができます。 - 最も重要な点
リストの要素(ポインタ)は、それ自体はQList
によって管理されますが、ポインタが指す先のオブジェクトのメモリは自動的に解放されません。 append(new Animal(...))
で、Animal
オブジェクトをヒープに動的に生成し、そのポインタをリストに追加します。QList<Animal*>
と宣言することで、Animal
オブジェクトへのポインタを格納します。
ループでの大量追加と reserve() の利用
大量の要素をappend()
で追加する場合、パフォーマンスに影響が出ることがあります。QList
は必要に応じて内部的にメモリを再割り当てしますが、これが頻繁に発生するとオーバーヘッドになります。reserve()
関数を使うと、事前に十分なメモリを確保し、再割り当ての回数を減らすことができます。
#include <QCoreApplication>
#include <QList>
#include <QDebug>
#include <QElapsedTimer> // 処理時間計測用
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
const int numElements = 1000000; // 100万個の要素
// 1. reserve() を使わない場合
QList<int> listWithoutReserve;
QElapsedTimer timer1;
timer1.start();
for (int i = 0; i < numElements; ++i) {
listWithoutReserve.append(i);
}
qDebug() << "Without reserve(): Time taken for" << numElements << "elements:" << timer1.elapsed() << "ms";
qDebug() << "Size:" << listWithoutReserve.size();
// 2. reserve() を使う場合
QList<int> listWithReserve;
listWithReserve.reserve(numElements); // 事前に100万個分のメモリを確保
QElapsedTimer timer2;
timer2.start();
for (int i = 0; i < numElements; ++i) {
listWithReserve.append(i);
}
qDebug() << "With reserve(): Time taken for" << numElements << "elements:" << timer2.elapsed() << "ms";
qDebug() << "Size:" << listWithReserve.size();
return a.exec();
}
出力例 (環境によって変動します)
Without reserve(): Time taken for 1000000 elements: 30 ms
Size: 1000000
With reserve(): Time taken for 1000000 elements: 15 ms
Size: 1000000
- 出力例では、
reserve()
を使うことで処理時間が半分程度に短縮されているのがわかります。 - これにより、
append()
が呼び出されるたびに内部的なメモリ再割り当てが発生する頻度が大幅に減り、特に大量のデータを扱う場合にパフォーマンスが向上します。 reserve(numElements)
を呼び出すことで、QList
はnumElements
個の要素を格納するのに十分なメモリを事前に確保します。
QList
に要素を追加する方法はいくつかあり、それぞれ利点があります。
QList::operator<< (const T &value)
これは append()
と全く同じ機能を持ちますが、より簡潔な記述が可能です。特に複数の要素を連続して追加したい場合にコードが読みやすくなります。
書式
QList<T> &operator<<(const T &value)
例
#include <QCoreApplication>
#include <QList>
#include <QString>
#include <QDebug>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QList<QString> fruits;
qDebug() << "--- operator<< ---";
// append() と同じように末尾に追加される
fruits << "Apple";
fruits << "Banana";
fruits << "Cherry";
// 複数の要素をチェーンして追加することもできる
fruits << "Date" << "Elderberry" << "Fig";
qDebug() << "Fruits List:" << fruits;
// 出力: Fruits List: ("Apple", "Banana", "Cherry", "Date", "Elderberry", "Fig")
return a.exec();
}
解説
- 内部的には
append()
を呼び出しています。 - 機能的には
append()
と全く同じです。
QList::push_back(const T &value)
append()
と完全に同じ機能を持つ、もう一つの関数です。C++のstd::vector
やstd::list
で一般的な命名規則に従っています。
書式
void push_back(const T &value)
例
#include <QCoreApplication>
#include <QList>
#include <QDebug>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QList<int> numbers;
qDebug() << "--- push_back ---";
numbers.push_back(100);
numbers.push_back(200);
numbers.push_back(300);
qDebug() << "Numbers List:" << numbers;
// 出力: Numbers List: (100, 200, 300)
return a.exec();
}
解説
- コードのスタイルや、他のC++コンテナとの一貫性を重視する場合に
push_back()
が選ばれることがあります。 append()
とpush_back()
は全く同じ実装であり、どちらを使っても結果は同じです。
QList::insert(int i, const T &value)
指定したインデックス i
に要素を挿入します。既存の要素は後ろにずれます。append()
は、実質的に insert(size(), value)
と同じ動作をします。
書式
void insert(int i, const T &value)
例
#include <QCoreApplication>
#include <QList>
#include <QString>
#include <QDebug>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QList<QString> colors;
colors.append("Red"); // ["Red"]
colors.append("Green"); // ["Red", "Green"]
colors.append("Blue"); // ["Red", "Green", "Blue"]
qDebug() << "Initial List:" << colors;
qDebug() << "\n--- insert ---";
// インデックス1に"Yellow"を挿入
colors.insert(1, "Yellow"); // ["Red", "Yellow", "Green", "Blue"]
qDebug() << "After insert(1, \"Yellow\"):" << colors;
// リストの先頭 (インデックス0) に挿入
colors.insert(0, "Purple"); // ["Purple", "Red", "Yellow", "Green", "Blue"]
qDebug() << "After insert(0, \"Purple\"):" << colors;
// リストの末尾に挿入 (append() と同じ効果)
colors.insert(colors.size(), "Orange"); // ["Purple", "Red", "Yellow", "Green", "Blue", "Orange"]
qDebug() << "After insert(size(), \"Orange\"):" << colors;
return a.exec();
}
出力例
Initial List: ("Red", "Green", "Blue")
--- insert ---
After insert(1, "Yellow"): ("Red", "Yellow", "Green", "Blue")
After insert(0, "Purple"): ("Purple", "Red", "Yellow", "Green", "Blue")
After insert(size(), "Orange"): ("Purple", "Red", "Yellow", "Green", "Blue", "Orange")
解説
- パフォーマンス的には、リストの中間への挿入は、その位置以降のすべての要素をずらす必要があるため、
append()
やpush_front()
よりも時間がかかる傾向があります(要素数に比例して時間がかかる O(N))。リストの先頭と末尾への挿入は高速です(償却定数時間 O(1))。 insert()
は、リストの中間や先頭に要素を追加したい場合に非常に便利です。
QList::prepend(const T &value)
リストの先頭に要素を追加します。既存の要素はすべて後ろにずれます。
書式
void prepend(const T &value)
例
#include <QCoreApplication>
#include <QList>
#include <QString>
#include <QDebug>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QList<QString> items;
items.append("Item C"); // ["Item C"]
items.append("Item D"); // ["Item C", "Item D"]
qDebug() << "Initial List:" << items;
qDebug() << "\n--- prepend ---";
items.prepend("Item B"); // ["Item B", "Item C", "Item D"]
qDebug() << "After prepend(\"Item B\"):" << items;
items.prepend("Item A"); // ["Item A", "Item B", "Item C", "Item D"]
qDebug() << "After prepend(\"Item A\"):" << items;
return a.exec();
}
出力例
Initial List: ("Item C", "Item D")
--- prepend ---
After prepend("Item B"): ("Item B", "Item C", "Item D")
After prepend("Item A"): ("Item A", "Item B", "Item C", "Item D")
解説
QList
は両端での高速な追加/削除に最適化されているため、prepend()
もappend()
と同様に非常に高速です(償却定数時間 O(1))。prepend()
は、リストの先頭に要素を追加したい場合に便利です。
QList::operator+=(const QList<T> &other) および QList::operator+(const QList<T> &other) const
別の QList
の内容を結合して追加することができます。
書式
QList<T> &operator+=(const QList<T> &other) // 既存のリストに結合
QList<T> operator+(const QList<T> &other) const // 新しいリストを生成して結合
例
#include <QCoreApplication>
#include <QList>
#include <QDebug>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QList<int> list1;
list1.append(1);
list1.append(2);
qDebug() << "List 1:" << list1; // (1, 2)
QList<int> list2;
list2.append(3);
list2.append(4);
qDebug() << "List 2:" << list2; // (3, 4)
qDebug() << "\n--- operator+= ---";
list1 += list2; // list1 に list2 の要素を追加
qDebug() << "List 1 after += List 2:" << list1; // (1, 2, 3, 4)
QList<int> list3;
list3.append(5);
list3.append(6);
qDebug() << "List 3:" << list3; // (5, 6)
qDebug() << "\n--- operator+ ---";
QList<int> combinedList = list1 + list3; // list1 と list3 を結合した新しいリストを生成
qDebug() << "Combined List (list1 + list3):" << combinedList; // (1, 2, 3, 4, 5, 6)
return a.exec();
}
解説
operator+
は、右辺と左辺のリストの要素を結合した新しいリストを返します。元のリストは変更されません。operator+=
は、右辺のリストの要素をすべて左辺のリストの末尾に追加し、左辺のリストを変更します。
QList::append()
はシンプルでよく使われる追加方法ですが、状況に応じてこれらの代替メソッドも検討すると、より効率的で読みやすいコードを書くことができます。
- 別のリストを結合
operator+=
,operator+
(元のリストを変更するか、新しいリストを作成するかで選択) - 任意のインデックスに挿入
insert()
- 先頭に単一要素を追加
prepend()
- 末尾に複数の要素を簡潔に追加
operator<<
- 末尾に単一要素を追加
append()
,push_back()
,operator<<
(好みに応じて)