问题
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:
Let's start at the top
class Helper { public: // Getters and setters are present! private: int i; std::map< -----------^Using
std::mapis oft troublesome with shared memory allocators because it does allocations right from within the constructor.boost::container::mapandboost::interprocess::mapdonot, 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 saidstd::map<K,V>.int, boost::interprocess::managed_shared_memory> shm; --------------------------------------------^Two points here:
boost::interprocess::managed_shared_memoryis not copyable (because it owns a shared memory resource). In my example I usedshared_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.it makes little sense to have standard-allocated containers in a
Helperclass 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>).
} -^Missing
;:)int main() { boost::interprocess::managed_shared_memory shmInfo(boost::interprocess::open_or_create, "Test", 1024); boost::interprocess::map -------------------------^Even though you now use
boost::interprocess::map, you still didn't indicate the allocator type. Again (as above), you can use theshared_mapalias.<int, Helper> -----------------------------------------^Missing
*for pointer result type.myMap = shmInfo.construct< boost::interprocess::map<int, Helper> >("Memory"); ----------------------------------------------------------------------------------------------------------------------^You forgot to invoke the constructor proxy object.
}Loose remarks:
- you need a constructor in Helper so you can pass the proper allocator instance to the constructor of the
shmfield - 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 theinner_alloc(forHelper::shm)
- you need a constructor in Helper so you can pass the proper allocator instance to the constructor of the
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