標準C++ライブラリのように記述された関数がどのように機能するかを知りたい場合(MSDNの説明だけでなく)。つまり、メモリをどのように割り当て、管理し、割り当てを解除して、結果を返すのかということです。それを理解するためにどこで、または何を知る必要がありますか?
5 に答える
ライブラリのヘッダーを見ることができます。ライブラリは高度にテンプレート化されているため、実際には多くの機能が実装されています(通常、テンプレートはヘッダーに実装する必要があります)。ヘッダーの場所はコンパイラーによって異なりますが、非常に簡単に見つけることができるはずです(たとえば、algorithmという名前のファイルを検索する)。
また、関連するすべてのヘッダーを表示するためにコードを前処理するようコンパイラーに要求することもできます(これにより、非常に長い出力が生成されます)。GCCを使用すると、これを行うことができますg++ -E yoursource.cc
。
探しているものがヘッダーに実装されていない場合は、ライブラリソースが必要です。ライブラリソースは通常、デフォルトでインストールされておらず、MSVCなどの商用コンパイラでも利用できません。glibc(Cライブラリ)とlibstdc ++(C ++ライブラリ)を探します。これらは、GCCやその他のコンパイラで使用されているものです。
いずれにせよ、(ユーザーのマクロとの名前の衝突を避けるために)変数名などで多くのアンダースコアが使用されているため、標準ライブラリの実装はかなり不可解である傾向があり、多くの場合、#ifdefや他のプリプロセッサがはびこっていることに注意してくださいがらくた。
C++ライブラリの作成に使用される手法を知っておく必要があります。BjarneStroustrupの本を手に入れることは良いスタートです。また、SGIには、適切に高いレベルの抽象化でSTLに関する非常に詳細なドキュメントがあります。
Windowsベースのものを調査する場合は、Windowsライブラリのシステム部分を調査することをお勧めします。
ウィンドウを補完するには:Posix仕様を理解することも重要です。
最初にいくつかの基本的なデータ構造の原則、次にアロケータに関するメモといくつかのリンク...
STLコンテナは、さまざまなデータ構造を使用します。マップ、セット、マルチマップ、およびマルチセットは通常、たとえば赤黒のバランシングルールを持つバイナリツリーとして実装されます。dequeは、配列の二重化または同様の成長パターンを利用して、配列内の循環キューである可能性があります(知識よりも印象的です)。 。
どのデータ構造も実際には標準で定義されていませんが、指定されたパフォーマンス特性によって選択肢が大幅に制限されます。
通常、含まれているデータは、ヒープに割り当てられたメモリに(デフォルトで)保持されているデータ構造ノードに直接含まれています。コンテナを指定するときにアロケータテンプレートパラメータを指定することで、ノードのメモリのソースをオーバーライドできます。これについては後で詳しく説明します。コンテナノードでアイテムを参照する(含まない)必要がある場合は、含まれるタイプとしてポインタまたはスマートポインタタイプを指定します。
たとえば、std :: setでは、ノードは、intと2つの子ポインター、およびライブラリに必要なメタデータ(たとえば、赤/黒のフラグ)用のスペースを持つバイナリツリーノードになります。バイナリツリーノードはアプリケーションのアドレス空間を移動しないため、必要に応じてデータアイテムへのポインタを別の場所に格納できますが、これはすべてのコンテナに当てはまるわけではありません。たとえば、ベクトルに挿入すると、すべてのアイテムが挿入の上に移動します。 1つずつ上に向けると、すべてのアイテムを移動して、ベクトル全体を再割り当てする必要がある場合があります。
コンテナクラスのインスタンスは通常非常に小さく、いくつかのポインタが一般的です。たとえば、std :: setなどには通常、ルートポインター、最低キーノードへのポインター、最高キーノードへのポインター、およびおそらくもう少し多くのメタデータがあります。
STLが直面する問題の1つは、ノードを作成/破棄せずに、複数アイテムのノードでインスタンスを作成および破棄することです。これは、たとえばstd::vectorとstd::dequeで発生します。厳密には、STLがそれをどのように行うかはわかりませんが、明らかなアプローチでは、新しく明示的なデストラクタ呼び出しを配置する必要があります。
新規配置を使用すると、すでに割り当てられているメモリにオブジェクトを作成できます。基本的にコンストラクターを呼び出します。パラメーターを受け取ることができるため、デフォルトのコンストラクターだけでなく、コピーコンストラクターまたは他のコンストラクターを呼び出すことができます。
デストラクタを作成するには、(正しく入力された)ポインタを介して、文字通りデストラクタを明示的に呼び出します。
((mytype*) (void*) x)->~mytype ();
これは、明示的なコンストラクターを宣言していない場合や、破棄する必要のない「int」などの組み込み型の場合でも機能します。
同様に、構築されたインスタンスから別のインスタンスに割り当てるには、operator=を明示的に呼び出します。
基本的に、コンテナは既存のノード内でデータをかなり簡単に作成、コピー、破棄できます。必要に応じて、メタデータはノードで現在構築されているアイテムを追跡します。たとえば、size()は、stdで現在構築されているアイテムを示します。 vector-現在のcapacity()によっては、追加の未構築アイテムが存在する場合があります。
編集-STLは、operator=ではなくstd:: swapを(直接または実際に)使用してデータを移動することで最適化できる可能性があります。これは、データ項目が(たとえば)他のSTLコンテナーであり、したがって大量の参照データを所有している場合に適しています。スワッピングにより、大量のコピーを回避できます。標準がこれを要求するのか、それとも許可するが義務付けないのかはわかりません。ただし、「特性」テンプレートを使用して、この種のことを行うためのよく知られたメカニズムがあります。デフォルトの「トレイト」は割り当てを使用する方法を提供できますが、特定のオーバーライドはスワッピング方法を使用して特殊なケースのタイプをサポートする場合があります。抽象化は、それが有効で破壊可能である限り、ソースに残っているもの(元のデータ、ターゲットからのデータなど)を気にしない動きになります。
もちろん、二分木ノードでは、ノードごとに1つのアイテムしかなく、常に構築されるため、これは必要ありません。
残りの問題は、ノードを作成/破棄するときに不要なコンストラクタ/デストラクタ呼び出しを取得せずに、ノード構造内に正しく配置され、適切なサイズのスペースを予約して、不明なタイプ(テンプレートパラメータとして指定)を保持する方法です。ユニオンは非POD型を保持できるため、これはC ++ 0xで簡単になり、便利な初期化されていないスペース型が得られます。それまでは、さまざまな程度の移植性で多かれ少なかれ機能するさまざまなトリックがあり、優れたSTL実装が学ぶための良い例であることは間違いありません。
個人的には、私のコンテナは型スペーステンプレートクラスを使用しています。コンパイラ固有の割り当てチェックを使用して、コンパイル時の配置を決定し、いくつかのテンプレートのトリックを使用して、正しいサイズのchars配列、shorts配列、long配列などから選択します。移植性のないアライメントチェックのトリックは「#ifdefined」などを使用して選択され、テンプレートはまだ許可されていないため、誰かが128ビットのアライメント要件をスローすると(コンパイル時に)失敗します。
実際にノードを割り当てる方法は?ほとんどの(すべて?)STLコンテナは、デフォルトで「allocator」に設定されている「Allocator」パラメータを取ります。その標準実装は、メモリを取得してヒープに解放します。適切なインターフェイスを実装すると、カスタムアロケータに置き換えることができます。
それをすることは私がしたくないことであり、確かに私の机の上にStroustrups「C++プログラミング言語」がないわけではありません。アロケータクラスで満たす必要のある要件はたくさんありますが、少なくとも過去には(改善された可能性があります)、コンパイラのエラーメッセージは役に立ちませんでした。
グーグルはあなたがここを見ることができると言っていますが...
メモリを割り当て/解放するオペレーティング システム関数は、C++ 標準ライブラリとはあまり関係がありません。
標準ライブラリ コンテナは (デフォルトで) メモリに new と delete を使用し、ほぼ確実に独自のヒープ データ構造を管理するコンパイラ固有のランタイムを使用します。通常、このアプローチは、プラットフォーム固有のオペレーティング システム ヒープが大きなブロックの割り当てにより適している、典型的なアプリケーションの使用により適しています。
アプリケーション ヒープは、オペレーティング システム ヒープからメモリを割り当て/解放しますが、「どのように?」そして「いつ?」プラットフォーム固有およびコンパイラ固有の詳細です。
Win32 メモリ管理 API については、こちらをご覧ください...
http://msdn.microsoft.com/en-us/library/ms810603.aspx
必要に応じて、win64 に相当するものを見つけることができると確信しています。
私はこの本を持っていませんが、その説明によると、http://www.amazon.com/C-Standard-Template-Library/dp/0134376331には含まれています
-コンポーネントを使用および実装するための実践的なテクニック
これはあなたが望むものではありませんか?