Using STL containers for boost::interprocess::managed_shared_memory

孤街醉人 提交于 2020-01-21 18:53:51

问题


Consider the following situation:

class Helper
{
    public:
        // Getters and setters are present!
    private:
        int i;
        std::map<int, boost::interprocess::managed_shared_memory> shm;
}

int main()
{
    boost::interprocess::managed_shared_memory shmInfo(boost::interprocess::open_or_create, "Test", 1024);

    boost::interprocess::map<int, Helper> myMap = shmInfo.construct< boost::interprocess::map<int, Helper> >("Memory");
}

myMap (which is a map of int and Helper) is constructed on the shared_memory. In turn, I want Helper to hold a map of int and boost::interprocess::managed_shared_memory.

When I am trying to use std::map in Helper, I am getting compiler errors:

error C2248: 'boost::interprocess::basic_managed_shared_memory::basic_managed_shared_memory' : cannot access private member declared in class 'boost::interprocess::basic_managed_shared_memory'

How can I achieve this?


回答1:


Okay, here's a version that works Live On Coliru

Let me address some of the issues your code had:


  1. Let's start at the top

    class Helper
    {
        public:
            // Getters and setters are present!
        private:
            int i;
            std::map<
    -----------^
    
  2. Using std::map is oft troublesome with shared memory allocators because it does allocations right from within the constructor. boost::container::map and boost::interprocess::map donot, so you should prefer them when using Boost Interprocess allocators. Using a template alias, you can cut down on the complexity of declaring such a shared map:

    template <typename T> using shm_alloc = bip::allocator<T, bip::managed_shared_memory::segment_manager>;
    template <typename K, typename V> using shared_map = bip::map<K, V, std::less<K>, shm_alloc<std::pair<K const, V> > >;
    

    Now you can "just" say shared_map<K,V> where you would have previously said std::map<K,V>.

                      int, boost::interprocess::managed_shared_memory> shm;
    --------------------------------------------^
    
  3. Two points here:

    1. boost::interprocess::managed_shared_memory is not copyable (because it owns a shared memory resource). In my example I used shared_ptr<managed_shared_memory> to work around this. You could probably use raw pointers if you are sure the lifetime of the objects is going to be longer than that of the map that contains the pointer.

    2. it makes little sense to have standard-allocated containers in a Helper class that lives in shared memory (std::map will simply point to objects on the process-local heap and that leads to UB when referenced from another process). So you should specify a boost interprocess allocator to put the container elements into shared memory. For technical reasons, this implies you have to specify the key comparator (event though it's just the default, std::less<K>).

    }
    -^
    
  4. Missing ; :)

    int main()
    {
        boost::interprocess::managed_shared_memory shmInfo(boost::interprocess::open_or_create, "Test", 1024);
    
        boost::interprocess::map
    -------------------------^ 
    
  5. Even though you now use boost::interprocess::map, you still didn't indicate the allocator type. Again (as above), you can use the shared_map alias.

                                <int, Helper> 
    
    -----------------------------------------^ 
    
  6. Missing * for pointer result type.

                                              myMap = shmInfo.construct< boost::interprocess::map<int, Helper> >("Memory");
    
    ----------------------------------------------------------------------------------------------------------------------^ 
    
  7. You forgot to invoke the constructor proxy object.

    }
    
  8. Loose remarks:

    • you need a constructor in Helper so you can pass the proper allocator instance to the constructor of the shm field
    • using typedefs (or in my sample, template aliases) really makes your code a lot more maintainable.
    • note that we have two allocator instances here, the outer_alloc (for the Helpers map) and the inner_alloc (for Helper::shm)

Full Working Sample

#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/containers/map.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>

namespace bip = boost::interprocess;

using ShMemRef = boost::shared_ptr<bip::managed_shared_memory>;
template <typename T> using shm_alloc = bip::allocator<T, bip::managed_shared_memory::segment_manager>;
template <typename K, typename V> using shared_map = bip::map<K, V, std::less<K>, shm_alloc<std::pair<K const, V> > >;

class Helper
{
  public:
    using inner_alloc = shm_alloc<std::pair<int, ShMemRef>>;
    Helper(inner_alloc const& instance) : shm(instance) {}
  private:
    int i;
    shared_map<int, ShMemRef> shm;
};

int main()
{
    ShMemRef shmInfo = boost::make_shared<bip::managed_shared_memory>(bip::open_or_create, "Main", 1024);

    using outer_alloc = shm_alloc<std::pair<const int, Helper>>;
    outer_alloc oa_instance(shmInfo->get_segment_manager());

    shared_map<int, Helper>* myHelpers = shmInfo->construct<shared_map<int, Helper>>("Memory")(oa_instance);

    Helper::inner_alloc ia_instance(shmInfo->get_segment_manager());
    Helper helper1(ia_instance), helper2(ia_instance), helper3(ia_instance);
    myHelpers->emplace(1, helper1);
    myHelpers->emplace(2, helper2);
    myHelpers->emplace(3, helper3);
}


来源:https://stackoverflow.com/questions/26342351/using-stl-containers-for-boostinterprocessmanaged-shared-memory

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!