2011-02-04 7 views
6

動的アロケータを使用する前にコンテナのインスタンスに渡すことを可能にするSTL実装を知っている人はいませんか?動的/状態ベースのアロケータを使用するSTL実装ですか?

シナリオは、多数のプールプールを管理する一般的なメモリアロケータがあり、stl :: vectorのインスタンスごとに異なるメモリプールから各インスタンスを割り当てることです。

標準的なSTL実装の問題は、タイプごとにメモリプールを定義できるということです。つまり、int型のすべてのベクトルが同じプールから割り当てられます。

私はすでに状態を持つもの、つまりこのインスタンスを割り当てたいプールに対して、デフォルトのstl :: allocatorをスワップしましたが、これはstl :: listのようにうまく動作しませんデフォルトのctor

ライブラリに関する理由から、すべてのオブジェクトのctorに有効なプールがないため、ユーザーがstlコンテナを使用する前に 'メモリプールの設定'関数を呼び出す必要があります。

誰かがこの種のものをサポートする実装を見つけましたか?

+0

リストのヘッドノードをコンストラクタに割り当てるMicrosoft STLですか?理想的なSTL実装(読み込みGNU)は、空のコンテナを構築するときにメモリ割り当てを使用しません。 –

+0

マイクロソフトと私の両方のGNUポート(gcc 3.4.1)は両方とも、ctorにヘッドノードを割り当てます。 STLPortはそうではありませんので、これは私の要件をサポートしています。 – user176168

答えて

2

型付きアロケータでは、一般的なアロケータを下に使用して割り当てを実行できます。

アロケータは、これらの機能をサポートする必要がある:

pointer address (reference x) const; 
    const_pointer address (const_reference x) const; 
    pointer allocate (size_type n, allocator<void>::const_pointer hint=0); 
    void deallocate (pointer p, size_type n); 
    size_type max_size() const throw(); 
    void construct (pointer p, const_reference val); 

あなただけのメモリを割り当て、メモリの割り当てを解除する仕組みを持っていると仮定すると、あなたは上記の機能の一部を実装するためにそれを使用することができます。

割り当てられているアロケータの利点は、正確に同じサイズのアイテムをたくさん作成することがわかっているため、「ページ」を作成することができます。最大の問題は、allocate()が連続したバッファを返すように強制されていることです。

http://www.cplusplus.com/reference/std/memory/allocator/

あなたの質問はこれが十分でない理由としてまだ少しは不明です。 「一度」ロジックでメモリプールを初期化することができます。 (マルチスレッドの場合は、これを実現するためにboost :: onceを使うことができます)。

+0

同じアロケータの複数の異なるインスタンスが必要で、コンパイル時にそれらのインスタンスを切り替えるだけで十分な場合は、整数型またはタグ型の引数をテンプレート化アロケータに渡すこともできます。 – bdonlan

0

1つのオプションは、スレッドローカル変数を使用して、使用するメモリプールへのポインタを保持し、これをアロケータ実装で取得することです。 (boost::thread_specific_ptrを使用して)、例えば:

// Global variable 
boost::thread_specific_ptr<allocator_impl> real_allocator; 

struct set_allocator : boost::noncopyable { 
private: 
    allocator_impl *old; 
public: 
    set_allocator(allocator_impl *newAllocator) { 
     old = real_allocator.get(); 
     real_allocator.reset(newAllocator); 
    } 
    ~set_allocator() { 
     real_allocator.reset(old); 
    } 
}; 

template<typename T> 
struct myallocator { 
private: 
    real_allocator *delegate; 
public: 
    myallocator() { 
     delegate = real_allocator.get(); 
    } 
    T *allocate(size_t n, allocator<void>::const_pointer hint=0) 
    { 
     return delegate->allocate(sizeof(T), n, hint); 
    } 
    // Other mandatory STL Allocator functions and typedefs follow 
}; 

// later: 
allocator_impl *allocator = new allocator_impl(); 
set_allocator sa(allocator); // Set current allocator using RAII 
std::list<int, myallocator> mylist; // using *allocator as the backing allocator 

myallocatorが実装しなければならないAPIはhereに記載されています。

残念ながら、STL APIの制限のために、これはSTLを再実装することなく得ることができます。ただし、アロケータでオブジェクトのコンストラクタにどこかで渡すことができるサードパーティのライブラリがあるかもしれません。

1

標準STLの問題は 実装では、あなただけ int型の すなわち、すべてのベクトルのは 同じプールから割り当てるしまうタイプごとにメモリプールを定義することができるということです。

これは正確ではありません。 int要素を保持する異なるベクトルにそれぞれ異なるアロケータ型を持たせることができます。質問に関するしかし

、 -

誰もが使用前の容器の インスタンスに渡されるダイナミック アロケータを可能STL 実装を知っています。

- これはC++標準ライブラリ(STL)ではサポートされていないため、オブジェクト単位のアロケータが動作する実装が存在する可能性がありますが、移植性がありません。カスタムアロケータを使用する理由と方法の詳細な分析のために

は、具体的 項11 Scott Meyers'sブックEffective STLを参照してください:カスタムアロケータの合法的な使用を理解します。

4

私はあなたの質問について正確には分かりません。だから私は状態完全なアロケータのケースをカバーします。

C++ 03では、任意のアロケータは同じタイプの別のアロケータによって割り当てられたリソースを解放できなければなりません。

C++ 0xの標準は、実際にこの制限を削除し、状態フルアロケータがいる限り、彼らは彼ら以来アロケータ認識コンテナ(私はそれがSTLでパッケージ化すべてのコンテナをカバーだと思い、あるとしてSTLコンテナに渡すことができますモデル配列)。

たとえば、[allocator.adaptor] $20.10 Class scoped_allocatorはC++ 0x STLの一部になりました。

0

しかし、STLポートは、Microsoft(VS 2008)とGNU実装(stl circa gcc 3.4.1のポート)では、このような機能をサポートしていないようです。 ctors/dtors。

これは私のテストコードです。それは完全な実装ではありません!

#include <list> 
#include <assert.h> 

namespace my 
{ 

class memory_pool 
{ 
public: 
    memory_pool() : m_top(0){}; 
    ~memory_pool(){}; 

    void* alloc(int size, int align) { void* p = (void*)&m_pool[m_top]; m_top += size; return p; } 
    void free (void* p) { assert((p >= m_pool) && (p < &m_pool[m_top])); } 
private: 
    char m_pool[0xFFFF]; 
    int m_top; 
}; 

template<class T> 
class dynamic_allocator 
{ 
    template<typename U> friend class dynamic_allocator; 
public: 
    typedef T     value_type;   
    typedef size_t    size_type;   
    typedef value_type*   pointer;    
    template <class _Tp1> struct rebind { typedef dynamic_allocator<_Tp1> other; }; 

    dynamic_allocator() : m_pPool(NULL){} 
    dynamic_allocator(memory_pool* pPool){ m_pPool = pPool; } 
    dynamic_allocator(const dynamic_allocator<T>& alloc) : m_pPool(alloc.m_pPool){} 
    template< typename U > 
    dynamic_allocator(const dynamic_allocator<U>& alloc) : m_pPool(alloc.m_pPool){} 
    ~dynamic_allocator() {} 

    pointer allocate(size_type count){ return allocate(count, NULL); } 
    pointer allocate(size_type count, const void*) { assert(m_pPool); return (pointer)m_pPool->alloc(count * sizeof(T), __alignof(T)); } 
    void deallocate(pointer p, size_type count) { assert(m_pPool); m_pPool->free(p); } 

    void set(memory_pool* pPool) { m_pPool = pPool; } 

private: 
    memory_pool* m_pPool; 
}; 

template< typename T, typename Al = dynamic_allocator<T> > 
class list : public std::list<T, Al> 
{ 
public: 
    typedef typename std::list<T, Al>::allocator_type allocator_type; 

    list() : std::list<T, Al>(){}; 
    list(const allocator_type& a) : std::list<T, Al>(a){}; 
    ~list(){}; 

    void initialise(memory_pool& pool){ std::list<T, Al>::_M_node.set(&pool); } // or something like this 
    void terminate(void){ clear(); std::list<T, Al>::_M_node.set(NULL); }     // or something like this 
}; 

}; // namespace my 

class lemon 
{ 
public: 
    lemon(){}  // must be empty ctor as we don't want to have active mem pool in ctor for users to use 
    ~lemon(){} 

    void initialise(my::memory_pool& pool){ m_list.initialise(pool); } 
    void terminate(void)     { m_list.terminate(); } 

    void add(float f) { m_list.push_back(f); } 

private: 
    my::list<float> m_list; 
}; 

int main(void) 
{ 
    my::memory_pool poolA; 
    my::memory_pool poolB; 

    my::dynamic_allocator<float> aa(&poolA); 
    my::list<float> a(aa); 
    my::list<float> fail; 

    std::list<float>::allocator_type bb; 
    std::list<float> b(bb); 

    a.push_back(0.2f); 
    b.push_back(50.0f); 
    //fail.push_back(19.0f); 

    a.clear(); 
    b.clear(); 

    lemon lemons[2]; 

    lemons[0].initialise(poolA); 
    lemons[1].initialise(poolB); 

    lemons[0].add(10.0f); 
    lemons[1].add(20.0f); 
    lemons[1].add(18.0f); 

    lemons[0].terminate(); 
    lemons[1].terminate(); 

    scanf("press any key\n"); 

    return 0; 
} 
関連する問題