14

カスタム アロケーターを選択するための STL コンテナー用のテンプレート パラメーターがあります。少し時間がかかりましたが、仕組みは理解できたと思います。与えられたアロケータの型は直接使用されず、別の型のアロケータに再バインドされるため、どういうわけかあまり良くありません。最後に、私はそれを扱うことができます。

APIを読んだ後、コンストラクターのパラメーターとしてアロケーターを指定する可能性もあることに気付きました。しかし、コンテナーがテンプレート パラメーターから指定されたアロケーターを内部的に再バインドする場合、コンテナーが使用するアロケーターの種類を知るにはどうすればよいでしょうか?

さらに、C++ 11 はスコープ付きアロケーターを使用するようになったことを読みました。これにより、コンテナーを含むコンテナーに対してコンテナーのアロケーターを再利用できます。スコープ付きアロケーターが有効なコンテナーの実装は、スコープ付きコンテナーを認識しないものとどのように大まかに異なりますか?

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

4

2 に答える 2

13

しかし、コンテナーがテンプレート パラメーターから指定されたアロケーターを内部的に再バインドする場合、コンテナーが使用するアロケーターの種類を知るにはどうすればよいでしょうか?

Allocator<T>コンストラクターには常に anを指定します (コンテナーのTthe はどこにありますか)。コンテナは、コンテナの内部データ構造が必要な場所value_typeにそれを変換します。このような変換コンストラクターを提供するには、次のように指定する必要があります。Allocator<U>UAllocator

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

さらに、C++ 11 はスコープ付きアロケーターを使用するようになったことを読みました。これにより、コンテナーを含むコンテナーのアロケーターを再利用できます。

より正確に言うと、C++11 にはと呼ばれるアロケータ アダプタscoped_allocator_adaptorがあります。

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

C++11 から:

クラス テンプレートscoped_allocator_adaptorは、コンテナーによって使用されるメモリ リソース (外部アロケーター) を指定する (他のアロケーターと同様に) アロケーター テンプレートであり、コンテナー内のすべての要素のコンストラクターに渡される内部アロケーター リソースも指定します。このアダプタは、1 つの外部アロケータ タイプと 0 個以上の内部アロケータ タイプでインスタンス化されます。1 つのアロケータ タイプのみでインスタンス化された場合、内部アロケータは scoped_allocator_adaptorしたがって、コンテナーとコンテナー内のすべての要素に同じアロケーター リソースを使用し、要素自体がコンテナーの場合は、それらの各要素を再帰的に使用します。複数のアロケーターでインスタンス化された場合、最初のアロケーターはコンテナーが使用する外部アロケーターであり、2 番目のアロケーターはコンテナーの要素のコンストラクターに渡され、要素自体がコンテナーである場合は、3 番目のアロケーターがコンテナーに渡されます。要素の要素など。コンテナーがアロケーターの数を超える深さまでネストされている場合、単一アロケーターの場合と同様に、残りの再帰に対して最後のアロケーターが繰り返し使用されます。[:scoped_allocator_adaptor外部アロケーター型から派生しているため、ほとんどの式で外部アロケーター型を置き換えることができます。—エンドノート]

したがって、コンテナーのアロケーターとして a を指定した場合にのみ、スコープ指定されたアロケーターの動作が得られscoped_allocator_adaptorます。

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

allocator_traits重要なのは、コンテナーがアロケーターを直接処理するのではなく、呼び出された新しいクラスを介してアロケーターを処理するようになったことです。また、コンテナは、コンテナ内の s の構築や破棄などの特定の操作に使用する必要があります。コンテナーは、アロケーターと直接対話してはなりません。allocator_traitsvalue_type

たとえば、アロケーターconstruct、指定された引数を使用して特定のアドレスで型を構築するというメンバーを提供できます。

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

アロケーターがこのメンバーを提供しない場合、allocator_traitsデフォルトの実装が提供されます。いずれにせよ、コンテナはこの関数を使用してすべての を構築する必要がありますが、 を介して使用し、を直接使用するのではありません。value_typeconstructallocator_traitsallocator

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

は、トレイトを利用して正しいアロケーターをコンストラクターに渡すscoped_allocator_adaptorカスタムconstruct関数を提供します。コンテナは、これらの詳細を幸いなことに知らないままです。コンテナーは、関数を使用して を構築する必要があることだけを認識しておく必要があります。allocator_traitsuses_allocatorvalue_typevalue_typeallocator_traits construct

ステートフル アロケータを正しく処理するために、コンテナが対処しなければならない詳細がさらにあります。これらの詳細も、コンテナーに仮定を行わず、 を介してすべてのプロパティと動作を取得させることで処理されますallocator_traitspointerコンテナはそれがであると想定することさえできませんT*。むしろ、このタイプは、それが何であるかを尋ねることによって見つかりallocator_traitsます。

つまり、C++11 コンテナーを構築するには、 を調べてallocator_traitsください。そして、クライアントがscoped_allocator_adaptor.

于 2012-09-23T23:51:00.497 に答える
4

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

スコープ付きアロケーターに関しては、非常に簡単に機能します。コンテナーは、一致するアロケーターを受け取るコンストラクターを持つメンバーがあるかどうかを判断します。この場合、使用したアロケーターを再バインドし、このアロケーターをメンバーに渡します。単純ではないのは、アロケーターが使用されているかどうかを判断するロジックです。メンバーがアロケーターを使用しているかどうかを判断するには、特徴std::uses_allocator<T, A>が使用されます。これTは、ネストされたtypedef allocator_typewhich および ifAをこの型に変換できるかどうかを判断します。メンバー オブジェクトの構築方法に関する規則は、20.6.7.2 [allocator.uses.construction] で説明されています。

実際には、これはアロケーターがコンテナーとそのメンバーに使用されるプールを処理するのに役立つことを意味します。コンテキストによっては、同じサイズのオブジェクトのプールを維持するために、ノードベースのコンテナなどに、同様のサイズのオブジェクトが割り当てられている場合にも合理的に機能する場合があります。ただし、アロケーターで使用されるパターンからは、それらが含まれているノードまたは一部の文字列の場合など、明確である必要はありません。また、異なる割り当てポリシーを使用するとタイプが変わるため、デフォルトの割り当てをそのまま使用するか、割り当てポリシーを実際に定義するポリモーフィック アロケーターのプロキシであるアロケーター タイプを使用するのが最も合理的です。もちろん、ステートフル アロケーターを使用した瞬間に、別のアロケーターを持つオブジェクトが存在する可能性があり、たとえばswap()それらが機能しない可能性があります。

于 2012-09-23T22:22:37.817 に答える