C++0xでは、std::allocator_traitsの導入によって、アロケーターに最低限必要なものが、かなり減った。これにより、アロケーター実装者の負担も減っている。メモ替わりに書いてみる。
以下は、std::allocator_traitsを通してアロケーターを使う場合に、最低限必要なものである。
// 必ずテンプレートパラメーターをひとつ取らなければならない // T型のオブジェクトに対するアロケーター template < typename T > class allocator { public : // 最低限必要なnested type typedef T value_type ; // ストレージの確保用 // n個のT型のオブジェクトを確保できるに足るだけのストレージを返す value_type * allocate( std::size_t n ) ; // ストレージの解放用 // pが指すn個のストレージを解放する void deallocate( value_type * p, std::size_t n ) ; // DefaultConstructibleである必要はない // コピーできなければならない // 例外を投げてはならない allocator( allocator const & ) noexcept ; // ムーブできなければならない // 例外を投げてはならない // 必要に応じて、ムーブコンストラクターも追加 // template argumentの違う他の型からの変換関数、コピーとムーブが両方可能であること // 例外を投げてはならない template <class U> allocator( allocator<U> const & ) noexcept ; // デストラクターは例外を投げてはならない // これは、STLの決まりごと ~allocator() noexcept ; // 他のオブジェクトと比較できなければならない // template argumentの違う他の型とも、比較できなければならない // a == bにおいて、お互いのallocateで確保したストレージが、お互いのdeallocateで解放できる場合、trueを。 // そうでない場合、falseを返す template < typename U > bool operator == ( allocator<U> const & ) ; // ==演算子の否定を返す template < typename U > bool operator != ( allocator<U> const & ) ; } ;
この他のメンバー、たとえばconstructとかdestroyとか、細々としたnested typesなどは、std::allocator_traitsを通して使う場合、適当に補完される。実を言うと、allocateやdeallocateも補完されるのだが、通常のユーザーが、自前アロケーターを書く目的は、そこにはないだろう。
追記、value_typeという名前のnested typeが必要であった。
boost::poolでアロケーターを置き換えてみるとわかるんですが、標準でベンダーが提供しているアロケーターの性能が結構良い事に驚きます。
ReplyDeleteというか売り物だからチューニングしてて当たり前か。
std::vectorとstd::listで最適なアロケーターが違っていたりするのも興味深いですが、今時なら「CPU買い換えろ!」の一言で済んでしまいそうなのが怖い。
亀コメントですみません。
ReplyDeleteallocate(n)とdeallocate(p, n)は補完されないように規格書からは読めたのですが、それは読み違いですか?
補完?
ReplyDeleteもちろん、これは宣言だけですから、定義をする必要があります。
ああ、ただし、今はコピーコンストラクターがある場合は、ムーブコンストラクターは暗黙に宣言されないので、明示的に書く必要がありますね。
ReplyDeleteまあ、2年前のドラフト規格をもとに書いた文章なので。