destroy_ptrでハマる

いや、まさかこうなるとは思ってなかったのでメモ。Managed Memory Segmentsはconstructしたオブジェクトをdestroyする必要があります。これはconstruct方法によっていろいろ選べます。例えばnamed instanceとして作成した場合、destroyを使って名前を指定して削除するか、destroy_ptrでポインタを指定して削除。anonymous instanceとして作成した場合はdestroy_ptrで削除。unique instanceならばdestroyにipc::unique_instanceを渡して削除できます。

namespace ipc = boost::interprocess;

ipc::managed_heap_memory heap(65536);

int* named_object     = heap.construct<int>("Int Object")(42);
int* unique_object    = heap.construct<int>(ipc::unique_instance)(42);
int* anonymous_object = heap.construct<int>(ipc::anonymous_instance)(42);

heap.destroy("Int Object");
heap.destroy<int>(ipc::unique_instance);
heap.destroy_ptr(anonymous_object);

で、使い方的にはanonymous_instanceは同型オブジェクトを複数個作成したい場合、つまり不特定数、オブジェクトを作るような場合に便利だと思います。というかanonymous_instanceの使い方はnew/deleteと同じですね。上記の2つ(named/unique instance)が特殊なだけで。

destroy_ptrはvoidポインタでは駄目

てっきりdestroy_ptrはvoid*で取るのかな、と思ったんですがちゃんと型を必要とするそうです(内部でアラインチェックなどのassertをいくつか引っかけたりしている)。なので以下のようなコードはassertに引っかかります。

void* void_object = heap.construct<int>(ipc::anonymous_instance);
heap.destroy_ptr(void_object); // assert! alignがどうとか書かれるはず

なので、anonymous instanceを扱う時はvoidポインタで削除しないように、確保した型をちゃんと扱うように気を付けましょう。
どうしてこんなことでハマったかというと、unique_ptrやshared_ptrで管理しようとして、void*で受け取ってdestroy_ptrを呼ぶデリータを書いてしまったからです。気を付けるためのメモでした。

追記)さらに抽象クラスも駄目

よくある話、抽象クラスや基底クラスを使ったコンテナとかで管理することもありますが抽象クラスを用いてdestroy_ptrを呼び出そうとするとコンパイルエラーになります。内容としてはboost::alignment_ofをdestroy_ptrに渡された型でインスタンス化しようとするのでもちろんできません。
# また確認してませんが、基底クラスでは派生先のクラスとサイズが異なる場合は上記のassertに引っかかると思われます。

struct base
{
    virtual ~base();
    virtual void foo()=0;
};
struct derive : public base {};

base* ptr = heap.construct<derive>(ipc::anonymous_instance)();
heap.destroy_ptr(ptr); // Error! "抽象クラスをインスタンス化できません"

とすると、vectorなどのコンテナへ一括管理する場合type erasureのお世話にならないといけないと思います。