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 を入れる代わりに、QVector8のみQListを管理します。
ドキュメントがQList適切なデフォルト コンテナを呼び出し始めたとき、事態はあらゆる割合でうまくいきませんでした。そうではありません。元のSTLの状態:
VectorSTL コンテナー クラスの中で最も単純で、多くの場合、最も効率的です。
Scott Meyer の効果的な STLstd::vectorには、"Prefer over..."で始まる項目がいくつかあります。
一般的に正しいことは、Qt を使用しているからといって、C++ が突然間違っているわけではありません。
Qt 6 では、その特定の設計ミスが修正されます。QVectorそれまでの間、またはを使用してstd::vectorください。