2017-04-05 13 views
4

私は割り当てられたバイト数を追跡​​するいくつかのクラスの別のインスタンスへの参照で、アロケータを書いています。カスタムアロケータの同じ状態を複数のコンテナに渡すにはどうすればよいですか?

は、私がやろうとしていることの最小限の例です(hereから適応されています)。代わりに、今まで割り当てられたバイトを収集するいくつかのintを参照しました。この参照は、メインの内側に割り当てられますとCustomAllocatorに渡される必要があります。

#include <limits> // numeric_limits 
#include <iostream> 
#include <typeinfo> // typeid 

// container 
#include <vector> 
#include <list> 
#include <forward_list> 

template<typename T> 
class CustomAllocator { 
public: 
    // type definitions 
    typedef T value_type; /** Element type */ 
    typedef T* pointer; /** Pointer to element */ 
    typedef T& reference; /** Reference to element */ 
    typedef const T* const_pointer; /** Pointer to constant element */ 
    typedef const T& const_reference; /** Reference to constant element */ 
    typedef std::size_t size_type; /** Quantities of elements */ 
    typedef std::ptrdiff_t difference_type; /** Difference between two pointers */ 

    template<typename U> 
    struct rebind { 
     typedef CustomAllocator<U> other; 
    }; 

    // return maximum number of elements that can be allocated 
    size_type max_size() const throw() { 
     return std::numeric_limits<std::size_t>::max()/sizeof(T); 
    } 

    CustomAllocator(std::size_t& memAllocated) : 
      m_totalMemAllocated(memAllocated) { 
     std::cout << "construct " << typeid(T).name() << std::endl; 
    } 

    CustomAllocator(const CustomAllocator& src) : 
      m_totalMemAllocated(src.m_totalMemAllocated) { 
     std::cout << "copy construct " << typeid(T).name() << std::endl; 
    } 

    template<class U> 
    CustomAllocator(const CustomAllocator<U>& src) : 
      m_totalMemAllocated(src.getTotalMemAllocated()) { 
    } 

    // allocate but don't initialize num elements of type T 
    pointer allocate(size_type num, const void* = 0) { 
     m_totalMemAllocated += num * sizeof(T); 
     // print message and allocate memory with global new 
     std::cout << "allocate " << num << " element(s)" << " of size " 
       << sizeof(T) << std::endl; 
     pointer ret = (pointer) (::operator new(num * sizeof(T))); 
     std::cout << " allocated at: " << (void*) ret << std::endl; 
     return ret; 
    } 

    // deallocate storage p of deleted elements 
    void deallocate(pointer p, size_type num) { 
     m_totalMemAllocated -= num * sizeof(T); 
     // print message and deallocate memory with global delete 
     std::cout << "deallocate " << num << " element(s)" << " of size " 
       << sizeof(T) << " at: " << (void*) p << std::endl; 
     ::operator delete((void*) p); 
    } 




    // initialize elements of allocated storage p with value value 
    // no need to call rebind with this variadic template anymore in C++11 
    template<typename _U, typename ... _Args> 
    void construct(_U* p, _Args&&... args) { 
     ::new ((void *) p) _U(std::forward<_Args>(args)...); 
    } 

    // destroy elements of initialized storage p 
    template<typename _U> 
    void destroy(_U* p) { 
     p->~_U(); 
    } 

    // return address of values 
    pointer address (reference value) const { 
     return &value; 
    } 
    const_pointer address (const_reference value) const { 
     return &value; 
    } 

private: 
    std::size_t& m_totalMemAllocated; 
}; 

template<typename T, typename U> 
bool operator==(const CustomAllocator<T> a, const CustomAllocator<U>& b) { 
    return true; 
} 

template<typename T, typename U> 
bool operator!=(const CustomAllocator<T>& a, const CustomAllocator<U>& b) { 
    return false; 
} 

int main() { 

    std::size_t memAllocated = 0; 

    CustomAllocator<int> allocatorInstance(memAllocated); 

    std::vector<int> foo(allocatorInstance); 
    foo.push_back(23); 
    foo.push_back(12); 
    foo.push_back(8); 

    std::cout << "---" << std::endl; 

    // here the same 
    std::list<double> bar(allocatorInstance); 
    bar.push_back(3.44); 
    bar.push_back(1.18); 
    bar.push_back(2.25); 

    std::cout << "---" << std::endl; 

    // debug output 
    for (auto x : foo) 
     std::cout << x << " "; 
    for (auto x : bar) 
     std::cout << x << " "; 

    std::cout << "\nalloc_count: " << memAllocated << std::endl; 

    std::cout << '\n'; 
    return 0; 
} 
ここに私の問題は、私はにアロケータインスタンスの(例m_totalMemAllocatedでは)まったく同じ状態を渡す方法がわからないということです

他の2つのコンテナ(ここではfooとbar)。標準では、C++ 11のアロケータは状態を持つことができると述べているためです。

更新:

は、これまでのところ、私はあなたが通常のstdコンテナにテンプレート引数としてCustomAllocatorsを渡すことを知っている:)

答えてくれてありがとう。このように:

std::vector<int, CustomAllocator<int> > foo; 
std::list<double, CustomAllocator<double> > bar; 

も参照してください。 Difference between allocator supplied as template parameter and allocator supplied as constructor argument in C++ containers?

が、ここで私は一緒に渡すことができないんだ状態とデフォルトコンストラクタは、私は私がない限り使用できないと呼ばれるになるだろう持っています参照をいくつかのデフォルト値を与える(しかし、それは私が望むものではない)。

グローバルスコープにメインから

std::size_t memAllocated = 0; 

を置くことCustomAllocatorを使用するすべてのコンテナがグローバルに定義されmemAllocatedを使用して終了することを意味します。しかし、私はいくつかの追加のメモリまたはインスタンスmemAllocated2をもう一度いくつかの他のアロケータインスタンスに割り当てられるように、それを拡張したいと思います。

サイド注:STD-コンテナと異なるコンテナのアロケータのステートフルバージョンについては

How to track memory usage using EASTL?

+1

単純な方法は、各アロケータインスタンスを「ステートレス」にし、タイプ自体が複数のインスタンスにわたってグローバルステートを保持するようにすることです。 – KABoissonneault

+0

Errr ...おそらく 'ベクトル'を意味するのではなく、 'ベクトル>'ですか? –

+1

このアロケータモデルを使用すると、アロケータインスタンスはステートレスである必要があります。しかし、C++ 17では、[str :: pmr]名前空間の中で、[*** p ** olymorphic ** m ** emory ** r ** esources *](http ://en.cppreference.com/w/cpp/memory/polymorphic_allocator)。 – BoBTFish

答えて

2

状態は、すべてのアロケータのインスタンス間で共有されていることを確認するにはを参照してください最初のアイデアは静的なメンバーにすることです。しかし、それだけでは十分ではありません。なぜなら、異なるテンプレートインスタンシエーションは、実際には異なるタイプであり、それぞれがスタティックメンバーの独自のコピーを持つからです。だから私は、唯一の2つの方法を想像することができます状態にのみ静的メンバを含むの補助クラスを作る、またはシングルトンパターンを使用する:の補助クラスの

静的メンバー:

struct CustomAllocatorState { 
    static std::size_t& m_totalMemAllocated; 
} 
std::size_t& CustomAllocatorState::m_totalMemAllocated = 0; # do not forget definition... 

template<typename T> 
class CustomAllocator { 
public: 
    ... 
    pointer allocate(size_type num, const void* = 0) { 
     CustomAllocatorState::m_totalMemAllocated += num * sizeof(T); 
     ... 

Singletonパターン(あなたは他を使用することができますC++シングルトンパターンは、この1つは)のろわれたシンプルですが、静的な初期化大失敗に抵抗しない:の補助クラスの

class CustomAllocatorState { 
    CustomAllocatorState(): m_val(0) {} 
    static CustomAllocatorState state; 

public: 
    int m_val; 
    static CustomAllocatorState& getState() { 
     return state; 
    } 
}; 
CustomAllocatorState CustomAllocatorState::state; 

template<typename T> 
class CustomAllocator { 
public: 
    ... 
    CustomAllocator() : 
     state(CustomAllocatorState::getState()) { 
      std::cout << "construct " << typeid(T).name() << std::endl; 
    } 
    ... 
    pointer allocate(size_type num, const void* = 0) { 
     state.m_totalMemAllocated += num * sizeof(T); 
     ... 
private: 
    CustomAllocatorState& state; 
}; 

静的メンバーは、おそらく簡単ですが、あなたはすでにあなたのアプリケーション内のシングルトンパターンを使用している場合、それできますここでもそれを使用しています。

関連する問題