I\'m creating a map (from string to string in this example) in shared memory using Boost.Interprocess. The compiler seems to want to force me, during retrieval from the map,
You can use a custom comparator
struct MyLess {
template
bool operator()(const T&t, const U&u) const
{
return t
In your code you can just typedef it as StringComparator
UPDATE To the comments
If you want to replace the std::map/boost::container::map with a Boost Multi Index container (which supports lookup by CompatibleKey), here's a demo of how to do it:
I've borrowed some of the idea's from the documentation section Emulating standard containers with multi_index_container.
Note that std::string as the lookup key still won't work, but you can easily use .c_strio() in that event.
Live On Coliru
#include
#include
#include
#include
#include
#include
#include
#include
namespace emulation {
template
struct mutable_pair
{
typedef T1 first_type;
typedef T2 second_type;
mutable_pair(Alloc alloc):first(T1(alloc)),second(T2(alloc)){}
mutable_pair(const T1& f,const T2& s):first(f),second(s){}
mutable_pair(const std::pair& p):first(p.first),second(p.second){}
T1 first;
mutable T2 second;
};
using namespace boost::multi_index;
template >
using map = multi_index_container<
Element,
indexed_by<
ordered_unique,Compare>
>,
typename Allocator::template rebind::other
>;
template >
using multimap = multi_index_container<
Element,
indexed_by<
ordered_non_unique,Compare>
>,
typename Allocator::template rebind::other
>;
template
struct wrap_map : map {
typedef map base_type;
typedef typename base_type::template nth_index<0>::type index_type;
wrap_map(Allocator alloc) : base_type({}, alloc)
{
}
wrap_map(Compare cmp, Allocator alloc) : base_type(
typename base_type::ctor_args_list{
typename index_type::ctor_args { typename index_type::key_from_value {}, cmp }
},
alloc)
{
}
};
}
// Typedefs of allocators and containers
namespace Shared {
typedef boost::interprocess::managed_shared_memory Segment;
typedef boost::interprocess::managed_shared_memory::segment_manager SegmentManager;
typedef boost::interprocess::allocator Allocator;
typedef boost::interprocess::allocator CharAllocator;
typedef boost::interprocess::basic_string, CharAllocator> String;
struct MyLess {
template bool operator()(const T &t, const U &u) const { return t < u; }
};
typedef MyLess StringComparator;
typedef boost::interprocess::allocator StringAlloc;
typedef emulation::mutable_pair MapItem;
typedef boost::interprocess::allocator MapItemAllocator;
typedef emulation::wrap_map Map;
}
int main(void) {
struct shm_remove {
shm_remove() { boost::interprocess::shared_memory_object::remove("MySharedMemory"); }
~shm_remove() { boost::interprocess::shared_memory_object::remove("MySharedMemory"); }
} remover;
// Create shared memory
Shared::Segment seg(boost::interprocess::create_only, "MySharedMemory", 65536);
Shared::Allocator alloc(seg.get_segment_manager());
// An instance of the string comparator, to construct the map
Shared::StringComparator cmp;
// Construct the shared memory map
Shared::Map *myMapPtr = seg.construct("myMap")(cmp, alloc);
myMapPtr->emplace(Shared::String("foo", alloc), Shared::String("bar", alloc));
myMapPtr->emplace(Shared::String("goo", alloc), Shared::String("car", alloc));
myMapPtr->emplace(Shared::String("hoo", alloc), Shared::String("dar", alloc));
Shared::String key("foo", alloc);
// This is the point of the exercise:
auto it = myMapPtr->find(key);
if (it!=myMapPtr->end())
std::cout << "Found: '" << it->first << "' -> '" << it->second << "'\n";
// this is now okay too
char szkey[] = "foo";
it = myMapPtr->find(szkey);
if (it!=myMapPtr->end())
std::cout << "Found: '" << it->first << "' -> '" << it->second << "'\n";
// this is now okay too
std::string skey("foo");
it = myMapPtr->find(skey.c_str());
if (it!=myMapPtr->end())
std::cout << "Found: '" << it->first << "' -> '" << it->second << "'\n";
return 0;
}
Prints:
Found: 'foo' -> 'bar'
Found: 'foo' -> 'bar'
Found: 'foo' -> 'bar'
Now, interestingly, Boost Container supports Scoped Allocators, so you could do away with the repeated passing of the allocators, however, Boost Multi Index sadly doesn't support it fully. Here's a halfway approach that's about as far as I could get it (still somewhat user friendlier):
Live On Coliru
#include
#include
#include
#include
#include
#include
#include
#include
#include
namespace emulation {
template
struct mutable_pair
{
typedef Alloc allocator_type;
typedef T1 first_type;
typedef T2 second_type;
mutable_pair(Alloc alloc):first(T1(alloc)),second(T2(alloc)){}
mutable_pair(const T1& f,const T2& s):first(f),second(s){}
mutable_pair(const std::pair& p):first(p.first),second(p.second){}
template
mutable_pair(const U& f,const V& s, Alloc2 alloc):first(f, alloc),second(s, alloc){}
T1 first;
mutable T2 second;
};
using namespace boost::multi_index;
template >
using map = multi_index_container<
Element,
indexed_by<
ordered_unique,Compare>
>,
typename Allocator::template rebind::other
>;
template >
using multimap = multi_index_container<
Element,
indexed_by<
ordered_non_unique,Compare>
>,
typename Allocator::template rebind::other
>;
template
struct wrap_map : map {
typedef map base_type;
typedef typename base_type::template nth_index<0>::type index_type;
wrap_map(Allocator alloc) : base_type({}, alloc)
{
}
wrap_map(Compare cmp, Allocator alloc) : base_type(
typename base_type::ctor_args_list{
typename index_type::ctor_args { typename index_type::key_from_value {}, cmp }
},
alloc)
{
}
};
}
// Typedefs of allocators and containers
namespace Shared {
typedef boost::interprocess::managed_shared_memory Segment;
typedef Segment::segment_manager SegmentManager;
typedef boost::container::scoped_allocator_adaptor > Allocator;
typedef Allocator::rebind::other CharAllocator;
typedef boost::interprocess::basic_string, CharAllocator> String;
struct MyLess {
template bool operator()(const T &t, const U &u) const { return t < u; }
};
typedef MyLess StringComparator;
typedef emulation::mutable_pair MapItem;
typedef Allocator::rebind::other MapItemAllocator;
typedef emulation::wrap_map Map;
}
int main(void) {
struct shm_remove {
shm_remove() { boost::interprocess::shared_memory_object::remove("MySharedMemory"); }
~shm_remove() { boost::interprocess::shared_memory_object::remove("MySharedMemory"); }
} remover;
// Create shared memory
Shared::Segment seg(boost::interprocess::create_only, "MySharedMemory", 65536);
Shared::Allocator alloc(seg.get_segment_manager());
// An instance of the string comparator, to construct the map
Shared::StringComparator cmp;
// Construct the shared memory map
Shared::Map *myMapPtr = seg.construct("myMap")(cmp, alloc);
myMapPtr->emplace("foo", "bar", alloc);
myMapPtr->emplace("goo", "car", alloc);
myMapPtr->emplace("hoo", "dar", alloc);
// This the only version I can get to work. But it forces you to create a
// copy of the key you are searching for, in the managed segment.
Shared::String key("foo", alloc);
// This is the point of the exercise:
auto it = myMapPtr->find(key);
if (it!=myMapPtr->end())
std::cout << "Found: '" << it->first << "' -> '" << it->second << "'\n";
// this is now okay too
char szkey[] = "foo";
it = myMapPtr->find(szkey);
if (it!=myMapPtr->end())
std::cout << "Found: '" << it->first << "' -> '" << it->second << "'\n";
// this is now okay too
std::string skey("foo");
it = myMapPtr->find(skey.c_str());
if (it!=myMapPtr->end())
std::cout << "Found: '" << it->first << "' -> '" << it->second << "'\n";
return 0;
}
Also printing
Found: 'foo' -> 'bar'
Found: 'foo' -> 'bar'
Found: 'foo' -> 'bar'