问题
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::map
is oft troublesome with shared memory allocators because it does allocations right from within the constructor.boost::container::map
andboost::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 saidstd::map<K,V>
.int, boost::interprocess::managed_shared_memory> shm; --------------------------------------------^
Two points here:
boost::interprocess::managed_shared_memory
is 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
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>
).
} -^
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_map
alias.<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
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 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