STLソースプロファイリング-カスタムallocatorの実装

3668 ワード

なぜallocatorが必要なのか
stl全体の操作オブジェクトはコンテナ内にあり、必ずスペース格納オブジェクトを構成する必要があります.通常、コンテナを使用するときにメモリがどのように割り当てられているかに関心がありません.
これはvectorヘッダファイルの定義です
template<
    class T,
    class Allocator = std::allocator
> class vector;

vectorを定義するときにallocatorを渡さないとデフォルトのstd::allocatorが使用されることがわかります.次に、allocatorの定義仕様に従って、メモリ、共有メモリ、ディスクストレージの簡単なスペースプロファイルを実現できます.
スペースコンフィギュレータの標準インタフェース
STLの仕様に従って、allocatorの必要なインタフェース
  • 各種typedef
  • allocator::value_type
    allocator::pointer
    allocator::const_pointer
    allocator::reference
    allocator::const_reference
    allocator::size_type
    allocator::difference_type
    allocator::rebind // class rebind      other;   typedef,  allocator
    
  • 初期化、アドレス関連関数
  • //     ,    n T  ,        ,      
    pointer allocator::allocate(size_type n, const void*=0)
    size_type allocator::max_size() const
    pointer allocator::address(reference x) const
    const_pointer allocator::address(const_reference x) const
    
  • 構築関数
  • void allocator::construct(pointer p, const T& x)
    void allocator::destory(pointer p)
    

    カスタムallocator
    定義allocator.h
    #include 
    #include 
    #include  // for exit()
    #include  // for UNIX_MAX
    #include 
    
    namespace test {
    
    template
    inline T* _allocate(ptrdiff_t size, T*) {
        std::cout << "_allocate called" << std::endl;
        set_new_handler(0);
        T* tmp = (T*)(::operator new((size_t)(size * sizeof(T))));
        if (NULL == tmp) {
            std::cerr << "out of memory" << std::endl;
            exit(0);
        }
        return tmp;
    }
    
    template
    inline void _deallocate(T* p) {
        ::operator delete(p);
    }
    
    template
    inline void _construct(T1* p, const T2& value) {
        ::new(p) T1(value);
    }
    
    template
    inline void _destroy(T* p) {
        p->~T();
    }
    
    template
    class Allocator
    {
    public:
        typedef T               value_type;
        typedef T*              pointer;
        typedef const T*        const_pointer;
        typedef T&              reference;
        typedef const T&        const_reference;
        typedef size_t          size_type;
        typedef ptrdiff_t       difference_type;
    
        template
        struct rebind
        {
            typedef Allocator other;
        };
    
        pointer allocate(size_type n, const void* hint=0) {
            return _allocate((difference_type)n, (pointer)0);
        }
    
        void deallocate(pointer p, size_type n) {
            return _deallocate(p);
        }
    
        void construct(pointer p, const T& value) {
            _construct(p, value);
        }
    
        void destroy(pointer p) {
            _destroy(p);
        }
    
        pointer address(reference x) {
            return (pointer)&x;
        }
    
        const_pointer address(const_reference x) {
            return (const_pointer)&x;
        }
    
        size_type max_size() const {
            return size_type(UINT_MAX/sizeof(T));
        }
    };
    
    } // end of namespace
    

    上でカスタマイズしたallocatorをコンテナに使用
    #include "allocator.h"
    
    #include 
    
    using namespace std;
    
    int main(int argc, char const *argv[])
    {
        cout << "allocator test" << endl;
        vector > v;
        v.push_back(1);
        v.push_back(2);
        for (int i = 0; i < v.size(); ++i)
        {
            cout << v[i] << endl;
        }
    
        return 0;
    }
    

    出力結果
    allocator test
    _allocate called
    _allocate called
    1
    2