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

内部的な型のアロケート

C++

C++11で導入されたライブラリのいくつかは、内部で使用する型のオブジェクトをアロケートするアロケータを、公開インタフェースとして要求します。

たとえば、std::function<R(Args...)>

template <class F, class Alloc>
void function::assign(F&& f, const Alloc& alloc);

std::functionは、関数オブジェクト型Fを内部的にアロケートします。

たとえば、std::shared_ptr<T>

template <class Y, class Deleter, class Alloc>
shared_ptr(Y* p, Deleter d, Alloc a);

std::shared_ptrは、内部で参照カウンタをアロケートします。参照カウンタの型はprivateなので、ユーザーは型名がわかりません。

こういうインタフェースに対しては、てきとうな要素型のアロケータオブジェクトを渡します。std::allocator<int>でもstd::allocator<MyClassType>でもかまいません。 そして、これらの関数の内部で、適切な要素型にアロケータをrebindされ、それらの要素型のオブジェクトがアロケートされます。

std::functionの例:

#include <iostream>
#include <functional>

int ident(int x) { return x; }

int main()
{
  std::function<int(int)> f;

  // 関数とアロケータを代入。
  //
  // ※ここではint型を対象とするアロケータを渡しているが、
  // 内部で適切な関数の型にrebindして使われる。
  f.assign(ident, std::allocator<int>());

  int result = f(1);
  std::cout << result << std::endl;
}

std::shared_ptrの例:

#include <iostream>
#include <memory>

int main()
{
    std::shared_ptr<int> p = {
        new int(3),
        std::default_delete<int>(),
        std::allocator<void>()
    };

    std::cout << *p << std::endl;
}

これらの関数の仕様上、rebindすることは明確に記載されてはいないのですが、Allocator requirementsを満たすアロケータ型を要求してるという点と、rebindを使うしか方法がない、という可能性の検討の結果、rebindを使うということがわかります。

std::functionstd::shared_ptrのほか、std::promiseもアロケータをrebindします。std::promiseは内部的にstd::shared_ptrを作りますが、そのことが公開インタフェースにはなっていないからです。