C++11では、std::allocator_traits
というアロケータアクセスの中間インタフェースが用意されたおかげで、自作アロケータに必要な実装がだいぶ減りました。
自作アロケータに必要な最小コードは、以下のようになります。
- 要素型
value_type
- 特殊関数(デフォルトコンストラクタ、コピーコンストラクタ、ムーブコンストラクタ)
- 別な要素型のアロケータを受け取るコンストラクタ
allocate()
メンバ関数。(hintパラメータはあってもなくてもいい)deallocate()
メンバ関数operator==
とoperator!=
サンプルコード:
#include <new> template <class T> struct MyAllocator { // 要素の型 using value_type = T; // 特殊関数 // (デフォルトコンストラクタ、コピーコンストラクタ // 、ムーブコンストラクタ) MyAllocator() {} // 別な要素型のアロケータを受け取るコンストラクタ template <class U> MyAllocator(const MyAllocator<U>&) {} // メモリ確保 T* allocate(std::size_t n) { return reinterpret_cast<T*>(std::malloc(sizeof(T) * n)); } // メモリ解放 void deallocate(T* p, std::size_t n) { static_cast<void>(n); std::free(p); } }; // 比較演算子 template <class T, class U> bool operator==(const MyAllocator<T>&, const MyAllocator<U>&) { return true; } template <class T, class U> bool operator!=(const MyAllocator<T>&, const MyAllocator<U>&) { return false; } #include <vector> #include <list> int main() { std::vector<int, MyAllocator<int>> v = {1, 2, 3}; std::list<int, MyAllocator<int>> ls = {4, 5, 6}; }
std::allocator_traits
クラスは、オブジェクトの構築(construct()
)、オブジェクトの破棄(destroy()
)、要素型の再束縛(rebind
)、一度にメモリ確保できる最大量(max_size()
)、その他メンバ型に関するデフォルト実装を用意してくれています。
自作アロケータにそれらの関数を持たせた場合はそれが使われます。持っていない場合にデフォルト実装が使われます。
GCCは4.8.2時点でstd::list
とstd::deque
のstd::allocator_traits
対応が不十分なため、これらのコンテナに最小コードのアロケータを渡すと、コンパイルエラーになります。
Clangは3.0時点で、このコードは通りました。