2012-09-23 9 views
14

カスタムアロケータを選択するSTLコンテナのテンプレートパラメータがあります。それはしばらくかかりましたが、私はそれがどのように機能するのか理解していると思います。与えられたアロケータ型は直接使用されていないが、別の型のアロケータにリバウンドされているので、どうやらこれは本当にいいことではない。最後に私はそれを扱うことができます。STLコンテナ:コンストラクタのアロケータパラメータとスコープ付きアロケータ

APIを読んだあと、アロケータをコンストラクタパラメータとして与える可能性もあることを認識しました。しかし、テンプレートパラメータから与えられたアロケータを内部的に再バインドする場合、どのような種類のアロケータがコンテナに使用されているかをどのように知っていますか?

さらに、C++ 11では、スコープ付きアロケータを使用して、コンテナのアロケータをそのコンテナに再利用できるようになりました。スコープ付きアロケータ対応コンテナの実装は、スコープ付きコンテナを認識しないコンテナとは大きく異なります。

残念ながら私はこれを説明できるものは見つかりませんでした。答えをありがとう!

答えて

13

しかし、どのように私はそれ が内部テンプレートパラメータから与えられたアロケータを再バインドした場合、コンテナは、使用するアロケータの種類を知っているのですか?

常に(Tが容器のvalue_typeある)コンストラクタにAllocator<T>を供給する。コンテナはそれをAllocator<U>に変換する必要があります。ここで、Uはコンテナの内部データ構造です。Allocatorは、例えば、そのような変換コンストラクタを供給する必要がある:

template <class T> class allocator { 
    ... 
    template <class U> allocator(const allocator<U>&); 

さらに私はC++ 11は現在 が含む容器のための容器のアロケータを再利用することを可能にするスコープアロケータを使用していることを読み取ります。

まあ、より正確には、C++ 11がscoped_allocator_adaptorと呼ばれるアロケータアダプタあり:C++ 11から

template <class OuterAlloc, class... InnerAllocs> 
class scoped_allocator_adaptor : public OuterAlloc 
{ 
    ... 
}; 

を:

クラステンプレートscoped_allocator_adaptorがあります コンテナによって使用されるメモリリソース(外部アロケータ)を指定するアロケータテンプレート (他のアロケータと同様)コンテナ内のすべての要素 のコンストラクタに渡されるアロケータリソースを内部の として指定します。このアダプタは、1つの外部と0以上の内部アロケータ型の でインスタンス化されます。 アロケータ型の1つだけでインスタンス化された場合、内部アロケータは scoped_allocator_adaptorとなり、コンテナ内およびコンテナ内のすべての要素に対して同じアロケータ リソースを使用し、要素自体がコンテナである場合は その要素は再帰的に です。複数のアロケータでインスタンス化した場合、最初の アロケータは容器で使用するために外側の割当である、第二 アロケータは、コンテナの要素のコンストラクタに渡さ と、要素自体がコンテナである場合、第三のアロケータはです が要素の要素に渡されます。容器はアロケータの数よりも大きい深さまで を入れ子になっている場合、最後アロケータ が残っ 再帰ため、単一アロケータの場合のように、繰り返し使用されます。 【:それはほとんどの式で外側アロケータ タイプに置換することができるようにscoped_allocator_adaptorを 外側アロケータ型に由来します。 - エンドノート]

あなたのコンテナのアロケータとしてscoped_allocator_adaptorを指定するのであれば、あなたは唯一のスコープアロケータの動作を取得。

スコープ付きアロケータ対応コンテナ の実装は、スコープ付きコンテナを認識しないものとどのように異なるのですか?

キーは、アロケータを直接処理するのではなく、allocator_traitsという新しいクラスを使用してアロケータを処理することが重要です。 は、コンテナにvalue_typeを作成して破棄するなどの特定の操作には、allocator_traitsを使用する必要があります()。 のコンテナは、はアロケータに直接話してはいけません。例えば、アロケータ部材を提供することができる

は、与えられた引数を使用して特定のアドレスにタイプを構築することconstruct呼ば:

template <class T> class Allocator { 
    ... 
    template<class U, class... Args> 
     void construct(U* p, Args&&... args); 
}; 

アロケータは、このメンバーを提供しない場合、allocator_traitsを提供しますデフォルト実装。

allocator_traits<allocator_type>::construct(the_allocator, *ugly details*); 

scoped_allocator_adaptorallocator_traitsがこれに転送するカスタムconstructの機能を提供します。いずれにせよ、コンテナすべてvalue_typeのこのconstruct機能を使用して、しかしallocator_traitsを通してそれを使用して、直接allocatorを使用していないを構築する必要がありますuses_allocator形質を利用し、正しいアロケータをvalue_typeコンストラクタに渡します。コンテナは、これらの細部に恵まれないままです。コンテナはallocator_traits construct関数を使用してvalue_typeを構築する必要があることだけを知っていなければなりません。

ステートフルなアロケータを正しく処理するには、コンテナが処理しなければならない詳細があります。これらの詳細についても、コンテナには何の前提もなく、すべてのプロパティと動作をallocator_traits経由で取得することで対処します。コンテナは、pointerT*であるとも仮定できません。むしろこのタイプはそれが何であるかallocator_traitsを求めることによって見つけられる。

つまり、C++ 11コンテナを構築するには、allocator_traitsを調べてください。クライアントがscoped_allocator_adaptorを使用している場合、スコープ付きアロケータ動作を無料で取得できます。

4

コンテナによって使用されるアロケータのタイプは、そのコンストラクタ引数によって定義されます。コンテナのコンストラクタで期待されるのはこの型です。しかし、すべてのアロケータは、定義されているものとは異なるタイプのアロケータを提供できる必要があります。たとえば、std::list<T, A>の場合、予想されるアロケータはオブジェクトを割り当てることができますが、std::list<T, A>は実際にノードを割り当てる必要があるため、これらのオブジェクトを割り当てるために決して使用されません。つまり、アロケータはリバウンドして別の型を割り当てます。残念なことに、これにより、特定の型を提供するためにアロケータを使用することは難しくなります。アロケータが実際に提供する型はわかりません。

スコープ付きアロケータに関しては、まったく単純です:コンテナは、一致するアロケータを持つコンストラクタを持つメンバを持っているかどうかを判断します。この場合、使用したアロケータを再バインドし、このアロケータをメンバに渡します。それは単純ではありませんが、アロケータが使用されているかどうかを判断するロジックです。メンバーがアロケータを使用するかどうかを判断するには、std::uses_allocator<T, A>の特性が使用されます。Tにネストされたtypedef allocator_typeがあるかどうかを確認し、Aをこのタイプに変換できるかどうかを判断します。メンバオブジェクトの構築方法に関する規則は、20.6.7.2 [allocator.uses.construction]に記述されています。

実際には、これは、アロケータがコンテナとそのメンバーに使用されるプールを処理するのに便利であることを意味します。いくつかの状況では、同様のサイズのオブジェクトが割り当てられている場合、合理的である場合もあります。任意のノードベースのコンテナに対して、等しいサイズのオブジェクトのプールを保持することができます。しかしながら、それらが、例えば、含まれるノードまたはいくつかのストリングについてのものである場合、アロケータと共に使用されるパターンからは、必ずしも明確である必要はない。また、異なる割り当てポリシーを使用すると型が変更されるため、デフォルトの割り当てに固執するか、実際に割り当てポリシーを定義するポリモーフィックな割り当て子のプロキシであるアロケータ型を使用するのが最も合理的です。もちろん、ステートフルなアロケータを持つ瞬間に、異なるアロケータを持つオブジェクトを持つことができます。 swap()が動作しない可能性があります。

関連する問題