1. ホーム
  2. c++

[解決済み] polymorphic_allocator: いつ、なぜそれを使うべきか?

2022-04-26 12:01:54

質問

これ に関するドキュメントです。 cppreference , こちら はワーキングドラフトです。

の本当の目的は何なのか、正直言ってよく分かりませんでした。 polymorphic_allocator とか、いつ、なぜ、どのように使うべきかということです。

例として pmr::vector には次のような署名があります。

namespace pmr {
    template <class T>
    using vector = std::vector<T, polymorphic_allocator<T>>;
}

は何を意味しているのでしょうか? polymorphic_allocator を提供するか?このように std::pmr::vector に関しても、同様に提供します。 std::vector ? 今までできなかったことが、今できること?

そのアロケーターの本当の目的は何なのか、実際いつ使うべきなのか?

どのように解決するのですか?

cppreferenceからの選択引用です。

<ブロッククオート

この実行時ポリモーフィズムにより、polymorphic_allocator を使用するオブジェクトは、同一の静的アロケータ型にもかかわらず、実行時に異なるアロケータ型を使用したかのように振る舞うことができます。

通常のアロケーターの問題は、コンテナの型が変わってしまうことです。もしあなたが vector を特定のアロケータで使用する場合、そのアロケータを使用した Allocator テンプレート・パラメータを使用します。

auto my_vector = std::vector<int,my_allocator>();

ここで問題なのは、このベクトルがアロケータが異なるベクトルと同じ型ではないことです。例えば、デフォルトアロケータベクタを必要とする関数に渡すことはできませんし、アロケータタイプの異なる2つのベクタを同じ変数/ポインタに代入することもできません(例:

auto my_vector = std::vector<int,my_allocator>();
auto my_vector2 = std::vector<int,other_allocator>();
auto vec = my_vector; // ok
vec = my_vector2; // error

ポリモーフィックアロケータとは、テンプレート機構ではなく、動的ディスパッチによってアロケータの振る舞いを定義できるメンバーを持つ単一のアロケータタイプのことです。これによって、共通の型でありながら、特定のカスタマイズされたアロケーションを使用するコンテナを持つことができます。

アロケータの動作のカスタマイズは、アロケータに std::memory_resource * :

// define allocation behaviour via a custom "memory_resource"
class my_memory_resource : public std::pmr::memory_resource { ... };
my_memory_resource mem_res;
auto my_vector = std::pmr::vector<int>(0, &mem_res);

// define a second memory resource
class other_memory_resource : public std::pmr::memory_resource { ... };
other_memory_resource mem_res_other;
auto my_other_vector = std::pmr::vector<int>(0, &mes_res_other);

auto vec = my_vector; // type is std::pmr::vector<int>
vec = my_other_vector; // this is ok -
      // my_vector and my_other_vector have same type

私が考えるに、残された主な問題は std::pmr:: コンテナは、まだ同等の std:: コンテナをデフォルトのアロケータで使用します。コンテナで動作するインターフェイスを設計するときに、いくつかの決定をする必要があります。

  • 渡されたコンテナがカスタムアロケーションを必要とする可能性があるか?
  • もしそうなら、(任意のアロケーターを許容するために)テンプレート・パラメーターを追加すべきでしょうか、それともポリモーフィック・アロケーターの使用を義務付けるべきでしょうか?

テンプレートソリューションでは 任意の アロケータはポリモーフィックアロケータを含むが、他の欠点がある(生成されるコードのサイズ、コンパイル時間、コードをヘッダーファイルで公開しなければならない、さらなる型汚染の可能性、問題を外部に押し出すことになる)。一方、ポリモーフィックアロケータの解決策では、ポリモーフィックアロケータが が使われます。このため std:: コンテナはデフォルトのアロケータを使用し、レガシーコードとのインターフェイスに影響を与えるかもしれません。

通常のアロケータと比較すると、ポリモーフィック・アロケータには、memory_resource ポインタのストレージ・オーバーヘッド(これはおそらく無視できるものです)や、割り当てのための仮想関数ディスパッチのコストなど、いくつかの小さなコストが発生します。主な問題は、ポリモーフィックアロケータを使わないレガシーコードとの互換性の欠如でしょう。