c++boostipcshared-memoryinterprocess

c++ IPC Boost::Interprocess vector of classes containing map


I like to create a boost interprocess vector of classes containing maps. The following code is based on the Container of Container and Creating Vectors in shared memory example, but I feel very overwhelmed by combining these two tutorials. I think im stuck constructing "MyVec" in memory. After that, the code does not compile.

The reason behind this is, to load data in memory once and access it from different processes on demand.

Thank you! Simon

#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/containers/map.hpp>
#include <boost/interprocess/containers/vector.hpp>
#include <boost/interprocess/containers/string.hpp>

using namespace boost::interprocess;

// this is my original object
// goal: create a named shared memory object of std::vector<obj>
/*
class obj {
    public:
        int id = 0;
        std::string string = "NA";             //will switch to "char_string"
        std::map<int, std::string> map;
        bool equalsType(const int &input, const bool &inverse){
            if (id == -1)
            {
                return !inverse;
            }
            return id == input ? !inverse : inverse;
        };
}
*/

// Typedefs of allocators and containers
typedef managed_shared_memory::segment_manager segment_manager_t;
typedef allocator<void, segment_manager_t> void_allocator;
typedef allocator<int, segment_manager_t> int_allocator;
typedef allocator<char, segment_manager_t> char_allocator;
typedef basic_string<char, std::char_traits<char>, char_allocator> char_string;

// Definition of the map holding a int as key and string as mapped type
typedef std::pair<const int, char_string> map_value_type;
typedef allocator<map_value_type, segment_manager_t> map_value_type_allocator;
typedef map<int, char_string, std::less<int>, map_value_type_allocator> map_type;

class complex_data // "boost version" of obj class
{
    int id_;
    char_string char_string_;
    map_type map_type_;

public:
    // Since void_allocator is convertible to any other allocator<T>, we can simplify
    // the initialization taking just one allocator for all inner containers.
    complex_data(int id, const char *name, const void_allocator &void_alloc)
        : id_(id), char_string_(name, void_alloc), map_type_(void_alloc)
    {
    }
};

// Definition of the vector holding complex_data objects
typedef allocator<complex_data, segment_manager_t> complex_data_vector_allocator;
typedef vector<complex_data, complex_data_vector_allocator> complex_data_vector;
typedef vector<complex_data_vector, complex_data_vector_allocator> complex_data_vector_vector;

int main()
{
    // Remove shared memory on construction and destruction
    struct shm_remove
    {
        shm_remove() { shared_memory_object::remove("MySharedMemory"); }
        ~shm_remove() { shared_memory_object::remove("MySharedMemory"); }
    } remover;

    // Create shared memory
    managed_shared_memory segment(create_only, "MySharedMemory", 65536);

    // An allocator convertible to any allocator<T, segment_manager_t> type
    void_allocator alloc_inst(segment.get_segment_manager());

    // Starting from here I'm completely lost
    // Construct the shared vector and fill it
    complex_data_vector_vector *myVec = segment.construct<complex_data_vector_vector>("MyVector")(alloc_inst);

    for (int i = 0; i < 100; ++i)
    {
        // Both key(string) and value(complex_data) need an allocator in their constructors
        int key_object(i);
        map_value_type mapped_object(i, "test", alloc_inst);
        map_value_type value(key_object, mapped_object);
        // Modify values and insert them in the map

        myVec->push_back(value)
    }
}

Solution

  • You want to create a vector of classes but creating a vector of vector of classes.

    All you need is complex_data_vector, your complex_data_vector_vector is not needed.

    #include <boost/interprocess/managed_shared_memory.hpp>
    #include <boost/interprocess/allocators/allocator.hpp>
    #include <boost/interprocess/containers/map.hpp>
    #include <boost/interprocess/containers/vector.hpp>
    #include <boost/interprocess/containers/string.hpp>
    
    using namespace boost::interprocess;
    
    typedef managed_shared_memory::segment_manager segment_manager_t;
    typedef allocator<void, segment_manager_t> void_allocator;
    typedef allocator<int, segment_manager_t> int_allocator;
    typedef allocator<char, segment_manager_t> char_allocator;
    typedef basic_string<char, std::char_traits<char>, char_allocator> char_string;
    typedef std::pair<const int, char_string> map_value_type;
    typedef allocator<map_value_type, segment_manager_t> map_value_type_allocator;
    typedef map<int, char_string, std::less<int>, map_value_type_allocator> map_type;
    
    class complex_data
    {
        int id_;
        char_string char_string_;
        map_type map_type_;
    
    public:
        complex_data(int id, const char* name, const void_allocator& void_alloc)
            : id_(id)
            , char_string_(name, void_alloc)
            , map_type_(void_alloc)
        {
        }
    
        void set(int key, const char* value) {
            map_type_.insert(map_value_type{key, {value, map_type_.get_allocator()}});
        }
    };
    
    // Definition of the vector holding complex_data objects
    typedef allocator<complex_data, segment_manager_t> complex_data_allocator;
    typedef vector<complex_data, complex_data_allocator> complex_data_vector;
    
    int main()
    {
        // Remove shared memory on construction and destruction
        struct shm_remove {
            shm_remove() { shared_memory_object::remove("MySharedMemory"); }
            ~shm_remove() { shared_memory_object::remove("MySharedMemory"); }
        } remover;
    
        // Create shared memory
        managed_shared_memory segment(create_only, "MySharedMemory", 65536);
    
        // An allocator convertible to any allocator<T, segment_manager_t> type
        void_allocator alloc_inst(segment.get_segment_manager());
    
        complex_data_vector* myVec = segment.construct<complex_data_vector>("MyVector")(alloc_inst);
    
        for (int i = 0; i < 100; ++i) {
            myVec->emplace_back(i, "test", alloc_inst);
            complex_data& data = myVec->back();
            data.set(42, "Test");
        }
    
    }