質問

間違いなく、ほとんどのC ++プログラミングプロジェクトにSTLを使用することを選択します。質問は最近私に提示されましたが、「STLを使用しないケースはありますか?」...

考えれば考えるほど、STLを使用しないことを選択する場合があるかもしれないことに気づきました。たとえば、コードベースが長年続くと予想される、非常に大規模で長期的なプロジェクトです。 。おそらく、プロジェクトのニーズに正確に適合するカスタムコンテナソリューションは、初期オーバーヘッドの価値があるのでしょうか?あなたはどう思いますか、STLをしないことを選択するケースはありますか?

役に立ちましたか?

解決

組み込みシステムなどの厳格なメモリ要件を持つプロジェクトは、STLに適さない場合があります。これは、ヒープから取得したものやヒープに返されたものを制御および管理することが難しいためです。エヴァンが述べたように、適切なアロケーターを書くことはこれを助けることができますが、使用されるまたはメモリの断片化に関係するすべてのバイトをカウントしている場合、STLが最適化されているため、特定の問題に合わせたソリューションを手で回すのが賢明かもしれません最も一般的な使用法。

boost :: arrayやboost :: unordered_mapなど、現在の標準にはない適用可能なコンテナがより多く存在するため、特定の場合にSTLを使用しないことも選択できます。

他のヒント

STLを使用しない主な理由は次のとおりです。

  1. C ++の実装は古く、ひどいテンプレートをサポートしています。
  2. 動的メモリ割り当ては使用できません。

どちらも実際には非常にまれな要件です。

機能がSTLと重複する独自のコンテナをローリングする長期プロジェクトでは、メンテナンスおよび開発コストが増加するだけです。

stlを使用することには多くの利点があります。長期プロジェクトの場合、コストよりもメリットの方が重要です。

  1. 新しいプログラマーは、初日からコンテナを理解できるようになり、プロジェクト内の他のコードを学習する時間が増えました。 (有能なC ++プログラマが知っているようにSTLを既に知っていると仮定)
  2. コンテナ内のバグを修正すると、ビジネスロジックの強化に費やす可能性のある時間を無駄にし、無駄にします。
  3. ほとんどの場合、STLが実装されているのと同様に、それらを記述するつもりはありません。

そうは言っても、STLコンテナーは並行性をまったく処理しません。したがって、並行性が必要な環境では、Intel TBB並行コンテナーなどの他のコンテナーを使用します。これらは、さまざまなスレッドが同時にコンテナを変更することができ、コンテナへのアクセスをシリアル化する必要がないように、きめの細かいロックを使用してはるかに高度です。

通常、最善の策は、STLコンテナを手巻きのものに置き換えるのではなく、カスタムアロケータでSTLを使用することです。 STLの良い点は、使用した分だけお支払いいただくことです。

これは典型的なビルドと購入のシナリオだと思います。ただし、この場合、私は自分自身をロールバックする前に、ほぼ常に「購入」し、STL-またはより良いソリューション(おそらくBoostからの何か)を使用すると思います。使用するビルディングブロックではなく、アプリケーションの動作にほとんどの努力を集中する必要があります。

私は本当にそうは思いません。独自のコンテナを作成する際には、汎用アルゴリズムの力が大きすぎてあきらめられないため、STLと互換性のあるものにしようとさえします。独自のコンテナを作成し、そのすべてのアルゴリズムを特化するだけの場合でも、少なくとも名目上はSTLを使用する必要があります。これにより、すべてのソートアルゴリズムをsort(c.begin()、c.end())で呼び出すことができます。異なる動作をする場合でも、同じ効果を得るためにソートを専門とする場合。

Symbianのコーディング。

STLPortはSymbian 9をサポートしているため、STLを使用する場合は以前よりも弱く(「使用できない」というのはかなり説得力のあるケースです)、STLはすべてのSymbianライブラリに対して相反するため、 Symbianのように物事を行うよりも多くの問題。

もちろん、これらの理由から、Symbianのコーディングは「C ++プログラミングプロジェクト」ではないと主張されるかもしれません。

私が取り組んだプロジェクトのほとんどは、実際に使用可能なSTLのバージョンよりもコードベースが古いため、今は導入しないことにしました。

これが発生する可能性がある状況の1つは、STLから必要な機能を既に提供している外部ライブラリを既に使用している場合です。たとえば、私の会社はスペースの限られたエリアでアプリケーションを開発しており、すでにウィンドウツールキットにQtを使用しています。 QtはSTLに似たコンテナクラスを提供するため、STLをプロジェクトに追加する代わりにそれらを使用します。

紹介:

STLは優れたライブラリであり、多くの場合に役立ちますが、すべての状況を確実に解決できるわけではありません。 STLまたは!STLに答えるのは、「STLがあなたのニーズを満たしていますか?」と答えるようなものです

STLの長所

  • ほとんどの場合、STLには特定のソリューションに適合するコンテナーがあります。
  • よく文書化されている
  • それはよく知られています(プログラマーは通常それをすでに知っているので、プロジェクトに入るのは短くなります)
  • テスト済みで安定しています。
  • クロスプラットフォームです
  • すべてのコンパイラに含まれています(3番目のライブラリ依存関係は追加しません)
  • STLはすでに実装されており、準備ができています
  • STLは光沢があります...

STLのコントラスト

単純なグラフ、赤黒ツリー、または量子コンピューターを介した同時アクセスを管理するAIを備えた非常に複雑な要素のデータベースが必要であることは重要ではありません。実際、STLはそうではなく、すべてを解決することはありません。

以下の側面はほんの一例ですが、これらは基本的にこの事実の結果です。STLは制限のある実際のライブラリです。

  • Exceptions:例外のSTLリレー。したがって、何らかの理由で例外を受け入れることができない場合(安全性が重要など)、STLを使用できません。右!例外は無効にできますが、例外を中継するSTLの設計は解決されず、最終的にクラッシュします。

  • 特定の(まだ含まれていない)データ構造が必要:グラフ、ツリーなど。

  • 複雑さの特別な制約:STL汎用コンテナは、ボトルネックコードに最適ではないことがわかります。

  • 同時実行の考慮事項:同時実行が必要であり、STLは必要なものを提供しません(例:双方向の []演算子のため、リーダー/ライターロックを(簡単に)使用できません) 。はるかに高速なアクセス/検索/挿入/その他のために、マルチスレッドを活用してコンテナを設計することもできます。

  • STLはニーズに合う必要がありますが、その逆も当てはまります。STLのニーズを満たす必要があります。 1KのアンマネージRAMを備えた組み込みマイクロコントローラーで std :: vector を使用しようとしないでください。

  • 他のライブラリとの互換性:歴史的な理由から、使用するライブラリはSTLを受け入れない可能性があります(たとえば、QtWidgetsは独自のQListを集中的に使用します)。コンテナを両方向に変換するのが最善の解決策ではない場合があります。


独自のコンテナの実装

それを読んだ後、あなたは次のように考えることができます:" まあ、STLよりも私の特定のケースに対して何か良いことをするかもしれないと確信しています。"待ってください!

コンテナを正しく実装することは、非常に迅速に大きなタスクになります。動作するものを実装するだけでなく、次の作業が必要になる場合があります。

  • 制限、アルゴリズムの複雑さなどを含め、詳細に文書化します
  • バグを予想し、それらを解決する
  • 今後の追加ニーズ:ご存知のように、この機能が欠落している、タイプ間の変換など
  • しばらくして、リファクタリングしてすべての依存関係を変更したい場合があります(遅すぎますか?)
  • ....
  

コードは、コンテナのようなコードの奥深くで、実装に時間がかかるものであるため、慎重に使用する必要があります。


サードパーティライブラリの使用

非STLは必ずしもカスタムを意味するわけではありません。ネットにはたくさんの優れたライブラリがあり、その中には寛容なオープンソースライセンスもあります。

追加のサードパーティライブラリを追加するかどうかは別のトピックですが、検討する価値があります。

マルチスレッドコードでSTLを使用する際に問題が見つかりました。スレッド間でSTLオブジェクトを共有しない場合でも、多くの実装では、スレッドセーフでない構造(インターロックインクリメントスタイルの代わりに参照カウントに++を使用したり、スレッドセーフでないアロケーターを使用したり)を使用します。

これらの各ケースで、STLを使用して問題を解決することを選択しました(必要なものを取得するのに十分なフックがあります)。

独自のコレクションを作成することを選択した場合でも、イテレータでのみ動作するアルゴリズムおよびその他のSTL関数を使用できるように、イテレータのSTLスタイルに従うことをお勧めします。

私が見た主な問題は、非スロー演算子newに依存するレガシーコードと統合する必要があることです。

1984年頃にCのプログラミングを始めましたが、STLを使用したことはありません。長年にわたり、独自の関数ライブラリを展開してきましたが、STLがまだ安定していなかったり、クロスプラットフォームのサポートがなかったりしたときに進化し、成長してきました。私の共通ライブラリは、他の人(主にlibjpeg、libpng、ffmpeg、mysqlのようなもの)と他のいくつかのコードを含むように成長し、外部コードの量を最小限に抑えたいと思っています。 STLは素晴らしいものになったと思いますが、率直に言って、ツールボックスのアイテムには満足しており、この時点で他のツールをロードする必要はありません。しかし、新しいプログラマーがSTLを使用することで、すべてをゼロからコーディングすることなく実現できる大きな飛躍と限界を確かに見ています。

標準のC ++では、一部のイテレーター操作で例外をスローすることができます。その可能性は、場合によっては問題になる可能性があります。したがって、重要な操作に対して例外をスローしないことが保証されている独自の単純なコンテナを実装できます。

私より前に答えたほとんどすべての人がSTLコンテナに非常に熱心に思えたので、実際に遭遇した問題から、それらを使用しない正当な理由のリストをまとめることが有用だと思いました。

これらは、3つの大まかなカテゴリに合理的にグループ化できます。

1)効率が悪い

STLコンテナは通常、実行速度が遅く、ジョブに大量のメモリを使用します。この理由は、基礎となるデータ構造とアルゴリズムの一般的な実装に一部起因している可能性があり、追加のパフォーマンスコストは、手元のタスクに関係のないAPI要件の多くが必要とするすべての追加の設計制約に由来します。

メモリはCPUによってキャッシュ上で64バイトの行でアドレス指定されるため、無謀なメモリの使用とパフォーマンスの低下が同時に起こります。また、優位性への参照の局所性を使用しない場合、サイクルと貴重なKbを無駄にしますキャッシュメモリの。

たとえば、std :: listには、最適な4ではなく要素ごとに24バイトが必要です。

https://lemire.me/blog/2016/09/15/the-memory-usage-of-stl-containers-can-be-surprising/

これは、2つの64ビットポインター、1 intと4バイトのメモリパディングを実装することで実装されているためです。少量の連続メモリを割り当て、使用中の要素を個別に追跡するなどの基本的なことを行うのではなく、 1つのポインターに両方の反復方向を格納するポインターxorテクニック。

https://en.wikipedia.org/wiki/XOR_linked_list

プログラムのニーズに応じて、これらの非効率性は大きなパフォーマンスヒットにつながる可能性があります。

2)制限/クリーピング基準

もちろん、時々、問題は、完全に共通の関数、またはSTLで実装されていないコンテナクラス(たとえば、優先度キュー内の減少_min()など)が必要なことです。

一般的な方法は、コンテナをクラスにラップし、コンテナ外部の追加の状態やコンテナメソッドの複数の呼び出しで不足している機能を実装することです。これにより、望ましい動作をエミュレートできますが、パフォーマンスは大幅に向上しますコンテナの内部動作を拡張する方法がないため、データ構造の実際の実装よりも低く、O()の複雑さは高くなります。あるいは、minmaxヒープ、トライなど、特定のSTLコンテナで基本的に互換性のない2つ以上のものが同時に必要になるため、2つ以上の異なるコンテナをまとめてマッシュアップすることになります(不可知ポインタを使用できる必要があるため) )など。

これらのソリューションはく、他の非効率性に加えて追加される可能性がありますが、言語が進化している方法は、C ++の機能クリープに一致する新しいSTLメソッドのみを追加し、欠落しているコア機能を無視することです

3)並行性/並列性

STLコンテナはスレッドセーフではなく、同時実行ははるかに少なくなります。 16スレッドコンシューマCPUの現代では、驚くべきことに、現代の言語のデフォルトのコンテナ実装では、1996年のようなすべてのメモリアクセスの周りにミューテックスを記述する必要があります。これは、非自明な並列プログラムでは、メモリバリアがあると、スレッドが実行をシリアル化することを強制し、これらがSTL呼び出しと同じ頻度で発生する場合、並列パフォーマンスに別れを告げることができます。

要するに、STLは、パフォーマンス、メモリ使用量、機能、または並列性を気にしない限り、優れています。 STLはもちろん、これらの懸念事項のいずれにも拘束されず、読みやすさ、移植性、保守性、コーディング速度などの他の優先事項が優先されるため、完全に問題ありません。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top