読者です 読者をやめる 読者になる 読者になる

C++11での自作アロケータに必要な最小コード

C++

C++11では、std::allocator_traitsというアロケータアクセスの中間インタフェースが用意されたおかげで、自作アロケータに必要な実装がだいぶ減りました。

自作アロケータに必要な最小コードは、以下のようになります。

サンプルコード:

#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::liststd::dequestd::allocator_traits対応が不十分なため、これらのコンテナに最小コードのアロケータを渡すと、コンパイルエラーになります。

Clangは3.0時点で、このコードは通りました。