回答:
とstd::(w)string
STLコンテナーを排他的に使用してQtの同等物との間で変換することから始めましたが、すでに切り替えてQString
おり、ますますQtのコンテナーを使用していることがわかりました。
文字列に関してQString
は、に比べてはるかに完全な機能を提供しstd::basic_string
、完全にUnicode対応です。また、効率的にCOWを実装することもできます。
Qtのコンテナー:
QString
。これは、Qt foreach
マクロ(コピーを行う)を使用する場合、およびメタタイプまたはシグナルとスロットを使用する場合に非常に役立ちます。QDataStream
std::string
COWの論争を)。一部のSTL実装は特に悪いです。QTLの哲学はSTLとは異なります。これはJ.ブランシェットによって要約されています。「STLのコンテナーは未加工の速度に最適化されていますが、Qtのコンテナークラスは、利便性、最小限のメモリ使用量、最小限のコード拡張を提供するように注意深く設計されています。」
上記のリンクは、QTLの実装と使用される最適化についての詳細を提供します。
QList<double>
32ビットアーキテクチャでのメモリ使用のプロファイルを確認してください。
QVector
ではなく、プロファイリングを試みますQList
。QListにはかなりの説明があり、QListはオブジェクトへのポインタを格納するように設計されています。したがって、動的に作成された各doubleアイテムとこのアイテムへのポインターはに格納されQList
ます。QListは、ベクターとリンクされたリストの間の「中間」コンテナとして設計されています。メモリ/パフォーマンスが重要な場合のために設計されていません。
これは答えにくい質問です。それは本当に哲学的/主観的な議論に要約することができます。
言われていること...
「ローマにいるとき...ローマ人のように行動する」というルールをお勧めします
つまり、Qtの土地にいる場合は、Qtのようにコーディングします。これは、単に読みやすさや一貫性の問題だけではありません。すべてをstlコンテナーに格納した場合、どうなるかを考えてみてください。その場合、すべてのデータをQt関数に渡す必要があります。本当に物事をQtコンテナーにコピーしたり、Qtコンテナーからコピーしたりする一連のコードを管理しますか?コードはすでにQtに大きく依存しているため、stlコンテナーを使用してコードを「標準」にする必要はありません。そして、何か便利なものにそれを使いたいときはいつでも、それを対応するQtコンテナーにコピーしなければならない場合、コンテナーの要点は何ですか?
Qtコンテナーは、STLコンテナーよりも制限されています。STLの方が優れている例をいくつか示します(これらすべてが過去にヒットしたものです)。
QList
(ポインタベース)をしてQValueList
、Qtの3が持っていた(値ベース)QPtrList
とQValueList
、Qtの4が今持っているQList
、そしてすべてのようで、それの何QPtrList
か QValueList
)。push_back()
、ないappend()
; front()
、ではありませんfirst()
、...)を使用して、Qt 5への移植を回避します。Qt2-> 3とQt3-> 4の両方で移行、Qtコンテナーの変更は、最もコードチャーンを必要とするものの1つです。rbegin()
/rend()
、逆反復を順方向反復に対して対称にします。すべてのQtコンテナーがそれらを持っているわけではない(連想型コンテナーにはない)ので、逆反復は不必要に複雑です。insert()
、さまざまな、ただし互換性のあるイテレータータイプのstd::copy()
範囲があるため、必要な頻度ははるかに少なくなります。Allocator
テンプレート引数があり、Qt(forのforの必須)と比較して、カスタムメモリ管理は簡単です(typedefが必要)。EDIT 20171220:これにより、C ++ 11およびC ++ 17に続くアロケーター設計の進歩からQtが切り離されます。例:ジョンラコスの講演(パート2)。QLineEdit
s/QString/secqstring/
std::deque
。std::list
持っていsplice()
ます。私がを使用していることに気付いたときはいつでもstd::list
、それが必要だからですsplice()
。 std::stack
、std::queue
それらの基礎となるコンテナを適切に集約し、それを継承しないQStack
でQQueue
ください。QSet
のようstd::unordered_set
ではなく、のようstd::set
です。QList
あるだけで奇妙な。上記の多くはQtで非常に簡単に解決できますが、Qtのコンテナーライブラリは、現時点では開発の焦点が不足しているようです。
EDIT 20150106:C ++ 11のサポートをQt 5コンテナークラスに導入するためにある程度の時間を費やした後、作業に値しないと判断しました。C ++標準ライブラリの実装に組み込まれている作業を見ると、Qtクラスが追いつかないことは明らかです。私たちは今Qt 5.4をリリースしましたが、再割り当ての要素をQVector
まだ動かせず、持っていないemplace_back()
か、右辺値がありません-...push_back()
最近QOptional
、std::optional
代わりにクラステンプレートを拒否し、代わりに待っていました。同様にstd::unique_ptr
。この傾向が続くことを願っています。
QList
でしたstd::deque
。明らかに、私はドキュメントをざっと読み飛ばすべきではありませんでした。
QVector
crbegin
Qt 5.6以降、友人がいます
std::reverse_iterator
壊れたQHash
/ QMap
イテレーターを使用しないため)。固定することができない何もありませんが、私の見るEDITを 2015年からmapped_type
value_type
QVector
使用するint
ため、(64ビットシステムでも)31ビットサイズを制限するという事実をリストに追加する価値があります。さらに、INT_MAX
1バイトを超えるサイズの要素を格納することもできません。たとえば、x86_64 Linux gcc .size()
で最大のものQVector<float>
は536870907要素(2²⁹-5)でしたが、std::vector<float>
4294967295要素(2³²-1;これにはRAMが不足しているため、これ以上試行しませんでした(このサイズにはすでに16 GiBが必要です)) )。
これらの主張を実際の測定可能な現象に分解しましょう:
この文脈での主張は、Javaスタイルの反復はSTLスタイルよりも「簡単」であり、したがって、この追加のインターフェースによりQtの方が使いやすいということです。
Javaスタイル:
QListIterator<QString> i(list);
while (i.hasNext())
qDebug() << i.next();
STLスタイル:
QList<QString>::iterator i;
for (i = list.begin(); i != list.end(); ++i)
qDebug << *i;
Javaイテレータスタイルには、少し小さくてクリーンであるという利点があります。問題は、これが実際にはSTLスタイルではなくなったことです。
C ++ 11 STLスタイル
for( auto i = list.begin(); i != list.end(); ++i)
qDebug << *i;
または
C ++ 11 foreachスタイル
for (QString i : list)
qDebug << i;
これは非常に単純なので、他に何かを使用する理由はありません(C ++ 11をサポートしていない場合を除く)。
ただし、私のお気に入りは次のとおりです。
BOOST_FOREACH(QString i, list)
{
qDebug << i;
}
ご覧のように、このインターフェースは、すでに洗練された、合理化された、モダンなインターフェースの上に、追加のインターフェース以外に何ももたらしません。すでに安定していて使いやすいインターフェースの上に、不必要なレベルの抽象化を追加していますか?「もっと簡単」という私の考えではありません。
また、Qt foreachおよびjavaインターフェースはオーバーヘッドを追加します。それらは構造をコピーし、不必要なレベルの間接参照を提供します。これは多くのようには思えないかもしれませんが、それほど単純ではないインターフェースを提供するためにオーバーヘッドの層を追加するのはなぜですか?Javaには演算子のオーバーロードがないため、Javaにはこのインターフェースがあります。C ++はそうします。
Qtが与える正当化は、暗黙的共有問題であり、暗黙的でも問題でもありません。ただし、共有は必要です。
QVector<int> a, b;
a.resize(100000); // make a big vector filled with 0.
QVector<int>::iterator i = a.begin();
// WRONG way of using the iterator i:
b = a;
/*
Now we should be careful with iterator i since it will point to shared data
If we do *i = 4 then we would change the shared instance (both vectors)
The behavior differs from STL containers. Avoid doing such things in Qt.
*/
まず、これは暗黙的ではありません。1つのベクトルを別のベクトルに明示的に割り当てます。STLイテレーター仕様では、イテレーターがコンテナーに属していることが明確に示されているため、bとaの間に共有コンテナーを明確に導入しました。次に、これは問題ではありません。イテレータ仕様のすべてのルールが守られている限り、何も問題はありません。何かがうまくいかないときはここだけです:
b.clear(); // Now the iterator i is completely invalid.
Qtはこれを何かを意味するものとして指定します。たとえば、このシナリオから問題が新たに発生するようなものです。そうではありません。イテレータは無効にされ、複数の互いに素な領域からアクセスできるものと同じように、これはまさにその動作です。実際、これはQtのJavaスタイルのイテレータですぐに発生します。これは、ここで説明されているアンチパターンである暗黙の共有に大きく依存しているためです。この「最適化」がマルチスレッディングに向かっているフレームワークで使用されるのは特に奇妙に思われますが、それはあなたのためのマーケティングです。
これは少しトリッキーです。コピーオンライトと暗黙的な共有および成長戦略を使用すると、コンテナーが特定の時間に使用するメモリの量を実際に保証することが非常に困難になります。これは、強力なアルゴリズム保証を提供するSTLとは異なります。
私たちは知っている、ベクターのための無駄なスペースの最小バウンドがベクトルの長さの平方根であるが、Qtの中でこれを実装する方法はないように思えます。彼らがサポートするさまざまな「最適化」は、この非常に重要なスペース節約機能を妨げます。STLはこの機能を必要としません(ほとんどの場合、2倍の増加を使用しますが、これはより無駄が多くなります)が、必要に応じて少なくともこの機能を実装できることに注意することが重要です。
同じことは二重にリンクされたリストにも当てはまり、XOrリンクを使用して使用スペースを大幅に削減できます。繰り返しますが、成長とCOWの要件のため、Qtではこれは不可能です。
COWは確かに何かを軽くすることができますが、Boostによってサポートされるなどの侵入型コンテナもそうすることができ、Qtは以前のバージョンでこれらを頻繁に使用しましたが、使いにくく、安全でなく、負担を課すため、あまり使用されていませんプログラマーに。COWはそれほど煩わしくないソリューションですが、上記の理由により魅力的ではありません。
同じメモリコストまたはQtのコンテナよりも少ないSTLコンテナを使用できなかった理由はありません。同時に、どのくらいのメモリを無駄にするかを実際に知るという追加の利点があります。残念ながら、生のメモリ使用量で2つを比較することはできません。そのようなベンチマークは、さまざまなユースケースで大きく異なる結果を示すため、STLが修正するように設計された問題とまったく同じです。
可能な限り、コピーコストをかけずにQtコンテナーを使用しないでください。可能な限り、(おそらくラッパーまたは新しい構文を使用して)STLタイプの反復を使用してください。
Adding an unnecessary level of abstraction on top of an already stable and usable interface? Not my idea of "easier".
。QtのJavaスタイルのイテレータはC ++ 11に追加されていません。彼らはそれよりも古い。とにかく、Qt foreach(QString elem, list)
はC ++ 11のforeachまたはBOOST_FOREACHと同じくらい簡単で、C ++ 11以前の準拠コンパイラーで動作します。
So, as we can see, this interface gains us nothing except an additional interface, *on top of* an already sleek, streamlined, and modern interface. Adding an unnecessary level of abstraction on top of an already stable and usable interface? Not my idea of "easier".
(強調鉱山)これは、foreachのC ++ 11バージョンとBOOSTバージョンを見せた直後に言ったもので、Qtバージョンはこれらの2つのうちの1つから構築されているように聞こえますが、AFAICTはそうではありません。それはあなたが意図したものではないと確信していますが、それはそれがうまくいく方法です。したがって、「誤解を招く情報」です。
It's an additional layer of abstraction (and an unnecessary one) that bloats the interface, which is not easier.
何と比較するかはまだ不明です。C ++ 03イテレータ?C ++ 11イテレータ?BOOST_FOREACH?上記のすべて?
STLコンテナー:
Qtコンテナーは、コピーオンライトイディオムを使用します。
std::basic_string
C ++ 11でこの規格に準拠し、これに準拠していませんでした。
主な問題の1つは、QtのAPIがQtのコンテナーでデータを提供することを期待しているため、2つの間で変換を行うのではなく、単にQtコンテナーを使用することです。
また、すでにQtコンテナーを使用している場合は、STLヘッダーファイルを含めたり、STLライブラリーにリンクしたりする必要がないため、これらを排他的に使用する方が少し最適な場合があります。ただし、ツールチェーンによっては、とにかくそれが発生する可能性があります。純粋に設計の観点からは、一貫性は一般的に良いことです。
COWの違いに加えて、STLコンテナーはさまざまなプラットフォームではるかに広くサポートされています。作業を「主流」のプラットフォームに限定すれば、Qtは十分に移植可能ですが、STLは他の多くのあいまいなプラットフォーム(Texas InstrumentsのDSPなど)でも利用できます。
STLは単一の企業によって制御されるのではなく標準であるため、一般的に言えば、STLコードを簡単に読み、理解し、変更できるプログラマが増え、それらをサポートするためのリソース(本、オンラインフォーラム、会議など)が増えます。 Qtの場合よりもこれを行います。この理由だけでQtを避けなければならないということではありません。それだけで、他のすべての条件が等しい場合は、デフォルトでSTLを使用する必要がありますが、もちろんすべての条件が同じであることはほとんどないため、最も意味のある独自のコンテキストで決定する必要があります。
AlexKRの回答に関して:STLのパフォーマンスは制限内で保証されていますが、特定の実装では、プラットフォームに依存する詳細を利用してSTL を高速化できます。したがって、その意味では、プラットフォームごとに異なる結果が得られる可能性がありますが、明示的な保証(モジュロバグ)より遅くなることはありません。
私の5セント:Qtコンテナーは、さまざまなプラットフォームで同様に動作するはずです。STLコンテナはSTLの実装に依存しています。異なるパフォーマンス結果が得られる場合があります。
編集:
私はSTLが「遅い」とは言っていませんが、さまざまな実装の詳細の影響を指摘しています。
これを
確認してから、おそらくこれを確認してください。
そして、それはSTLの本当の問題ではありません。明らかに、パフォーマンスに大きな違いがある場合、STLを使用するコードに問題があります。
Qtの使い方次第ではないでしょうか。製品全体で使用する場合は、おそらくQtコンテナを使用するのが理にかなっています。(たとえば)UI部分のみに含める場合は、C ++標準コンテナーを使用する方がよい場合があります。
QVectorには(ときどき)大きな制限があります。メモリのintバイトのみを割り当てることができます(制限は要素数ではなくバイト単位であることに注意してください)。これは、QVectorで2GBを超える連続したメモリブロックを割り当てようとすると、クラッシュが発生することを意味します。これはQt 4および5で発生します。std:: vectorにはそのような制限はありません。
私にとってSTLコンテナーを使用する主な理由は、非常に大きなコンテナーでメモリを再利用するためにカスタムアロケーターが必要な場合です。たとえば、1000000エントリ(キーと値のペア)を格納するQMapがあるとします。Qtでは、それはnew
何であれ正確に1,000,000万の割り当て(呼び出し)を意味します。STLでは、常にすべてのメモリを一度に内部的に割り当てるカスタムアロケーターを作成し、マップにデータが入力されるときに各エントリに割り当てることができます。
私のアドバイスは、ビジネスロジックでパフォーマンスクリティカルなアルゴリズムを作成するときにSTLコンテナーを使用し、必要に応じて結果がUIコントロールとフォームに表示されるようになったら、それらをQtコンテナーに戻すことです。
QMapNode<K,V>
、自分用に特化してK
、自分用のV
を提供することができますoperator new
。