multi_indexなども使えて便利

ついつい見落としてましたが、interprocessはmulti_indexなどのinterprocess外ですがBoostのライブラリとして提供している一部のコンテナもmanaged memory segmentsを使って作成できるようです。ドキュメントに書いてあるのはmulti_indexとunordered_mapの2つ。恐らくそれ以外のBoost内のコンテナでアロケータ指定ができるものは使えそうです。managedクラスにはallocatorテンプレートが内部に宣言されており、multi_indexなどのクラステンプレートのアロケータとして指定してコンストラクタに渡すと使えます。

#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <iostream>

namespace bip = boost::interprocess;
namespace bmi = boost::multi_index;

struct user
{
    int  id;
    int  age;

    user( int _id, int _age ) : id(_id), age(_age) {}
};

struct id  {};
struct age {};

typedef bmi::multi_index_container<
    user,
    bmi::indexed_by< bmi::ordered_unique<bmi::tag<id>
                     , BOOST_MULTI_INDEX_MEMBER(user,int,id) >,
                     bmi::ordered_non_unique<bmi::tag<age>
                     , BOOST_MULTI_INDEX_MEMBER(user,int,age) >
    >,
    bip::managed_shared_memory::allocator<user>::type
> user_set;

int main()
{
    const std::size_t shm_size = 65536;

    struct shared_memory_deleter
    {
        shared_memory_deleter()  { bip::shared_memory_object::remove("MySharedMemory"); }
        ~shared_memory_deleter() { bip::shared_memory_object::remove("MySharedMemory"); }
    } shm_deleter;

    {
        bip::managed_shared_memory shm(bip::create_only,"MySharedMemory",shm_size);

        user_set* us = shm.construct<user_set>("MyMIndex")
                        (user_set::ctor_args_list(),shm.get_allocator<user>());
        if(!us)
            return -1;

        us->insert(user(5,19));
        us->insert(user(70,44));
        us->insert(user(50,20));
        us->insert(user(3,32));
        us->insert(user(36,29));
    }
    {
        bip::managed_shared_memory shm(bip::open_only,"MySharedMemory");

        user_set* us = shm.find<user_set>("MyMIndex").first;
        if(!us)
            return -1;

        user_set::const_iterator it = us->begin();
        while(it != us->end())
        {
            std::cout << "ID: " << it->id << " Age: " << it->age << std::endl;
            ++it;
        }
    }
}

multi_indexが使えるだけでも結構嬉しいです。そういう人も結構多いはず。

このアロケータの指定方法を使えばSTLも動くんじゃないの?

やってみましたが、やっぱり無理なようです。

#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/range/algorithm_ext/iota.hpp>
#include <boost/range/algorithm/for_each.hpp>
#include <vector>
#include <iostream>

namespace bip = boost::interprocess;

int main()
{
    typedef std::vector<int,bip::managed_shared_memory::allocator<int>::type> int_vector;
    const std::size_t shm_size = 65536;

    struct shared_memory_deleter
    {
        shared_memory_deleter()  { bip::shared_memory_object::remove("MySharedMemory"); }
        ~shared_memory_deleter() { bip::shared_memory_object::remove("MySharedMemory"); }
    } shm_deleter;

    {
        bip::managed_shared_memory shm(bip::create_only,"MySharedMemory",shm_size);

        int_vector* us = shm.construct<int_vector>("MyVector")
                            (100,0,shm.get_allocator<int>());
        if(!us)
            return -1;
        boost::iota(*us,0);
    }
    {
        bip::managed_shared_memory shm(bip::open_only,"MySharedMemory");

        int_vector* us = shm.find<int_vector>("MyVector").first;
        if(!us)
            return -1;
        boost::for_each(*us,[](int i){ std::cout << i << " "; });
    }
}

// --------
// コンパイル結果
error C2440: '=' : 'boost::interprocess::offset_ptr<PointedType>' から 'std::_Container_proxy *' に変換できません。	c:\program files\microsoft visual studio 10.0\vc\include\vector	442

内部でoffset_ptrで返却されていて、変換できないので駄目だそうです。

やっぱり使いづらい?

Twitter / cpp_akira: @krustf もうちょい抽象化されれば、Boost.Ser ...
Twitter / cpp_akira: bip::vector<X> v; ...
との意見を頂きましたが、やっぱり使いづらいですよね。constructの方法もあれだし、真面目にコンテナ使うとtypedefが長くてしんどいし。もうちょっと手軽にしてくれないかなあ…(いやこれまでもっと面倒だったものをここまでラップしてあるので贅沢言えないんですが。)なんかちょっと書いてみたい気はしますね。