QList
の配列ですvoid*
。
通常の操作でnew
は、ヒープ上の要素であり、それらへのポインターをvoid*
配列に格納します。リンク リストと同様に、リストに含まれる要素への参照 (ただし、リンク リストとは異なり、イテレータではありません!) は、要素がコンテナーから再度削除されるまで、すべてのコンテナーの変更の下で有効なままであることを意味します。したがって、名前は「リスト」です。このデータ構造は配列リストと呼ばれ、すべてのオブジェクトが参照型 (Java など) である多くのプログラミング言語で使用されます。これは、すべてのノードベースのコンテナーと同様に、非常にキャッシュに適していないデータ構造です。
ただし、配列リストのサイズ変更は、型に依存しないヘルパー クラス ( ) に組み込むことができますQListData
。これにより、実行可能なコードのサイズがいくらか節約されるはずです。QList
私の実験では、と のどちらが最も実行可能なコードを生成しないQVector
かを予測することはほぼ不可能です。std::vector
これは、 pimpl ポインター以外の何もない 、 などQString
の多くの Qt 参照のような型に適したデータ型でした。QByteArray
これらの型についてQList
、重要な最適化が行われました。型がポインターより大きくない場合 (この定義はプラットフォームのポインター サイズ (32 ビットまたは 64 ビット) に依存することに注意してください)、オブジェクトはヒープ割り当てオブジェクトではなく、void*
直接スロット。
ただし、これは型が自明に再配置可能である場合にのみ可能です。つまり、を使用してメモリ内で再配置できますmemcpy
。ここでの再配置とは、オブジェクトmemcpy
を別のアドレスに移動し、重要なことに、古いオブジェクトのデストラクタを実行しないことを意味します。
そして、これは物事がうまくいかなくなったところです。Java とは異なり、C++ ではオブジェクトへの参照はそのアドレスであるためです。また、元のでは、このプロパティが保持されなくなっQList
た配列にオブジェクトを配置することにより、オブジェクトがコレクションから再び削除されるまで、参照は安定していました。void*
これは、すべての意図と目的のための「リスト」ではなくなりました。
ただし、 a よりも厳密に小さい型を avoid*
に配置することも許可されたため、問題が発生し続けましたQList
。しかし、メモリ管理コードはポインタ サイズの要素を想定しているためQList
、パディング (!) を追加します。つまりQList<bool>
、64 ビット プラットフォームの a は次のようになります。
[ | | | | | | | [ | | | | | | | [ ...
[b| padding [b| padding [b...
キャッシュ ラインに 64 個の bool を入れる代わりに、QVector
8のみQList
を管理します。
ドキュメントがQList
適切なデフォルト コンテナを呼び出し始めたとき、事態はあらゆる割合でうまくいきませんでした。そうではありません。元のSTLの状態:
Vector
STL コンテナー クラスの中で最も単純で、多くの場合、最も効率的です。
Scott Meyer の効果的な STLstd::vector
には、"Prefer over..."で始まる項目がいくつかあります。
一般的に正しいことは、Qt を使用しているからといって、C++ が突然間違っているわけではありません。
Qt 6 では、その特定の設計ミスが修正されます。QVector
それまでの間、またはを使用してstd::vector
ください。