2010-10-09

アロケーターに最低限必要なもの

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が必要であった。

4 comments:

萌ゑ said...

boost::poolでアロケーターを置き換えてみるとわかるんですが、標準でベンダーが提供しているアロケーターの性能が結構良い事に驚きます。

というか売り物だからチューニングしてて当たり前か。

std::vectorとstd::listで最適なアロケーターが違っていたりするのも興味深いですが、今時なら「CPU買い換えろ!」の一言で済んでしまいそうなのが怖い。

Unknown said...

亀コメントですみません。
allocate(n)とdeallocate(p, n)は補完されないように規格書からは読めたのですが、それは読み違いですか?

江添亮 said...

補完?
もちろん、これは宣言だけですから、定義をする必要があります。

江添亮 said...

ああ、ただし、今はコピーコンストラクターがある場合は、ムーブコンストラクターは暗黙に宣言されないので、明示的に書く必要がありますね。
まあ、2年前のドラフト規格をもとに書いた文章なので。