18

カスタム allocatorを作成してN、いくつかの class の要素を格納するための大きなブロック (配列) を事前に割り当ててTから、配列内のインデックスを増やして、割り当て要求を処理します。

事前に割り当てられたブロック内の要素の初期化が必要ないため、次のようなものは機能しません。

T buffer[N];

この場合、のコンストラクターがブロックの要素Tに対して呼び出されるためです。N

私の理解では、のコンストラクターstd::aligned_storageは呼び出されないため、次のようなものを使用することを考えました。Tstd::aligned_storage

std::aligned_storage<
    N * sizeof(T),
    std::alignment_of<T>::value 
>::type buffer;

T* base = static_cast<T*>( static_cast<void*>(&buffer) );

そして、アロケータは、T の割り当てが要求されたときにベース ポインタをインクリメントするだけで (まで)、T は必要に応じて (placement を使用して) その(base+N)で構築できます。new

このスキームを使用して、STL コンテナーのカスタム アロケーターを定義したいと思います。ただし、ここで再バインドの問題が発生する可能性があるようです。実際、私の理解が正しければ、STL アロケータは type から type への再バインドをサポートする必要Tがあります。タイプ(ノードのその他の「ヘッダー」オーバーヘッド情報を含む)。では、前述のアプローチは再バインドにうまく機能しますか? または(私が思うに) s の正しい配置はそうではありませUstd::list<T>std::mapTUTstd::aligned_storageT別の異なるタイプの正しい配置を意味しますUか?

この問題はどのように解決できますか?

buffer前述を定義して、別のタイプへの再バインドにも機能させるにはどうすればよいUですか?

この問題は別の視点から取り組むべきでしょうか? もしそうなら、何?

4

1 に答える 1

13

あなたは正しい軌道に乗っています。

厄介な詳細の 1 つは、アロケーターのコピーを比較する必要があることです。等しいということは、互いのポインターの割り当てを解除できることを意味します。したがって、 などのコンテナstd::list<int>は に再バインドyour_alloc<int>し、を使用して をyour_alloc<node<int>>構築します。技術的には、によって割り当てられたポインターの割り当てを解除する必要があります。your_alloc<node<int>>your_alloc<int>your_alloc<node<int>>your_alloc<int>

これが、この要件を満たすための私の試みです。このコードを自由にコピー/変更/悪用してください。私の意図は教育することであり、世界のアロケーターのサプライヤーになることではありません (とにかく儲かるわけではありません:-))。

mallocこの例では、配置に対して少し異なるアプローチをとっています。関心のあるプラットフォーム (OS X、iOS) で16 バイトの配置されたメモリを返すことをたまたま知っているので、カスタム アロケータが返す必要があるのはそれだけです。その番号は、システムに適したものに変更できます。

この整列のハードワイヤリングは、単一のプールが複数のallocator<int>andを安全に供給できることを意味しますallocator<node<int>>。それらはすべて 16 バイトで整列されているためです (そしてそれで十分です)。また、コピーはすべて同じバッファーを共有するため、コピー (変換されたコピーであっても) がポインターがバッファーを指していることを検出できることも意味します。

少し言い方を変えれば、C++ 委員会は、アロケータが参照型であることを効果的に指定しました。コピーは同等であり、同じメモリ プールを指します。

アロケータに実際に埋め込まれたメモリプールを使用して不正行為を回避できますが、一部の実装では一部のコンテナのみであり、標準からの引用でそれを裏付けることはできません。

于 2013-03-19T00:49:31.120 に答える