今回はC++のアロケータを自分の作ったものを使おうというもの。
うーん・・・まあnew、deleteが遅いのがどうにも我慢ならんとか、その他もろもろの理由がある場合は使うのかもしれませんが、大して使う必要はないような・・・
それはさておきやってみましょう。
まずアロケータの簡単な説明。
コンテナ用のメモリ管理をするクラスallocatorのこと。メモリの確保/解放を行い、見えないところでよくお世話になっている。
STLのコンテナ、たとえばvectorも
template <class T, class Allocator=allocator<T>> class vector { … };
のようになっていて、実際に指定しないで使う場合はデフォルトのアロケータが用いられています。
つまり、アロケータの独自実装というのは、いつもはデフォルトのアロケータで行われているメモリの確保/解放を自分で明示的に処理を書いてそれを使って行おうということ。
ほら、どんどん不必要そうになってきた・・・
少しでもSTLのコンテナについて知るっていう勉強だと思ってやっているので問題なし!
というわけで、コードの一例。
#include <vector> #include <limits> #include <iostream> using namespace std; template <class T> class MyAllocator { public: typedef size_t size_type; typedef ptrdiff_t difference_type; typedef T* pointer; typedef const T* const_pointer; typedef T& reference; typedef const T& const_reference; typedef T value_type; /* アロケータをU型にバインドする */ template <class U> struct rebind { typedef MyAllocator<U> other; }; /* メモリを割り当てる */ pointer allocate(size_type num, const void* hint = 0) { return (pointer)( ::operator new(num * sizeof(T))); } /* 割り当て済みの領域を初期化する */ void construct(pointer p, const T& value) { new ((void*)p) T(value); } /* オブジェクトのアドレスを返す */ pointer address(reference value) const { return &value; } /* constなオブジェクトのアドレスを返す */ const_pointer address(const_reference value) const { return &value; } /* 初期化済みの領域を削除する */ void destroy(pointer p) { p->~T(); } /* メモリを解放する */ void deallocate(pointer p, size_type n) { ::operator delete((void*)p); } /* 割り当てることができる最大のサイズを返す */ size_type max_size() const throw() { /* numeric_limitsでsize_tのとりうる最大値を取得 */ return numeric_limits<size_t>::max() / sizeof(T); } }; int main(int argc, char* argv[]) { char a[] = {'a', 'b', 'c', 'd', 'e'}; /* 独自のアロケータを使用 */ vector<char, MyAllocator<char>> avec(a, a+5); avec.push_back('f'); for(int i=0; i<6; i++) cout << avec[i] << endl; return 0; }
とりあえずtypedefの部分は必須のものなのでデフォルトのものと全く同じ。
今回は動きがデフォルトのアロケータと同じになるように(多分)しました。メンバ関数の意味はコメントで大体はわかるかな。
しかし実のところ、このアロケータの独自実装。一つ問題があるんです。(コード例の問題じゃないよ)
vectorやdequeue以外のSTLのコンテナは内部に各要素を表現するための構造体を持っていて、もちろんこの『構造体』を確保しないと要素を動的に増やすことはできません。でも、最初に宣言して渡すアロケータのテンプレート引数の型はもちろんその『構造体』ではないですよね。
だから、渡したアロケータを使ってくれないのです。
というわけで、あまり役に立ちません。私が知らないだけだったらごめんなさい。