我正在使用 Boost.Interprocess 在共享内存中创建一个映射(在本示例中从字符串到字符串)。 编译器似乎想强制我在从映射检索期间在 托管段只是为了(不必要地)包含查询项。
我希望能够
通过将映射的键与非共享内存中已有的实例进行匹配,可以更有效地查找共享映射中的值,而无需执行此额外的分配。但它是
如果我尝试使用 std::string
或 const char *
作为 map 的 find
方法的参数,则拒绝编译。
(请参阅底部的编译器错误消息)。
我需要定义某种 我的共享内存 key 类型与其非共享等效 key 类型之间的比较器方法(本例中为 std::string )?如果是这样,应该怎样做 这看起来像什么,我应该如何让 map 使用它?如果没有,我该怎么办?
这是代码,后面是编译器错误。问题出在 main()
的底部。
// shmap2.cpp
#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>
//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< void, SegmentManager >
Allocator;
typedef boost::interprocess::allocator< char, SegmentManager >
CharAllocator;
typedef boost::interprocess::basic_string< char, std::char_traits< char >, CharAllocator >
String;
typedef std::less< String >
StringComparator;
// Definition of the shared map from String to String
// (To avoid confusion, let's strictly use Python-like definitions of "key", "value" and "item")
typedef std::pair< const String, String >
MapItem;
typedef boost::interprocess::allocator< MapItem, SegmentManager >
MapItemAllocator;
typedef boost::interprocess::map< String, String, StringComparator, MapItemAllocator >
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 );
// An allocator instance that can be converted to any allocator< T, Shared::SegmentManager > type
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< Shared::Map >( "myMap" )( cmp, alloc );
// Here's the problem:
// std::string key( "foo" ); // Compilation fails if you use this.
// char key[] = "foo"; // Compilation fails if you use this.
Shared::String key( "foo", 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.
// This is the point of the exercise:
Shared::Map::iterator it = myMapPtr->find( key );
return 0;
}
使用 std::string
作为键
:
$ g++ -o shmap2 -D BOOST_ALL_NO_LIB -I ../boost_1_57_0 shmap2.cpp
shmap2.cpp:79:40: error: no matching member function for call to 'find'
Shared::Map::iterator it = myMapPtr->find( key );
~~~~~~~~~~^~~~
../boost_1_57_0/boost/container/detail/tree.hpp:1089:13: note: candidate function not
viable: no known conversion from 'std::string' (aka 'basic_string<char,
char_traits<char>, allocator<char> >') to 'const key_type' (aka 'const
boost::container::basic_string<char, std::__1::char_traits<char>,
boost::interprocess::allocator<char, boost::interprocess::segment_manager<char,
boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family,
boost::interprocess::offset_ptr<void, long, unsigned long, 0>, 0>, iset_index> >
>') for 1st argument
iterator find(const key_type& k)
^
../boost_1_57_0/boost/container/detail/tree.hpp:1092:19: note: candidate function not
viable: no known conversion from 'std::string' (aka 'basic_string<char,
char_traits<char>, allocator<char> >') to 'const key_type' (aka 'const
boost::container::basic_string<char, std::__1::char_traits<char>,
boost::interprocess::allocator<char, boost::interprocess::segment_manager<char,
boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family,
boost::interprocess::offset_ptr<void, long, unsigned long, 0>, 0>, iset_index> >
>') for 1st argument
const_iterator find(const key_type& k) const
^
1 error generated.
使用const char *
作为键
:
$ g++ -o shmap2 -D BOOST_ALL_NO_LIB -I ../boost_1_57_0 shmap2.cpp
In file included from shmap2.cpp:17:
In file included from ../boost_1_57_0/boost/interprocess/containers/string.hpp:19:
../boost_1_57_0/boost/container/string.hpp:676:59: error: no matching constructor for
initialization of 'allocator_type' (aka 'boost::interprocess::allocator<char,
boost::interprocess::segment_manager<char,
boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family,
boost::interprocess::offset_ptr<void, long, unsigned long, 0>, 0>, iset_index> >')
basic_string(const CharT* s, const allocator_type& a = allocator_type())
^
shmap2.cpp:79:46: note: in instantiation of default function argument expression for
'basic_string<char, std::__1::char_traits<char>, boost::interprocess::allocator<char,
boost::interprocess::segment_manager<char,
boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family,
boost::interprocess::offset_ptr<void, long, unsigned long, 0>, 0>, iset_index> > >'
required here
Shared::Map::iterator it = myMapPtr->find( key );
^
../boost_1_57_0/boost/interprocess/allocators/allocator.hpp:140:4: note: candidate
constructor template not viable: requires single argument 'other', but no
arguments were provided
allocator(const allocator<T2, SegmentManager> &other)
^
../boost_1_57_0/boost/interprocess/allocators/allocator.hpp:129:4: note: candidate
constructor not viable: requires single argument 'segment_mngr', but no arguments
were provided
allocator(segment_manager *segment_mngr)
^
../boost_1_57_0/boost/interprocess/allocators/allocator.hpp:134:4: note: candidate
constructor not viable: requires single argument 'other', but no arguments were
provided
allocator(const allocator &other)
^
1 error generated.
更新:按照sehe的建议,下面,我尝试替换
typedef std::less< String >
StringComparator;
与
typedef struct
{
template< typename T, typename U >
bool operator()( const T & t, const U & u )
const { return t < u; }
} StringComparator;
但得到了相同的两个编译器错误。
最佳答案
您可以使用自定义比较器
struct MyLess {
template <typename T, typename U>
bool operator()(const T&t, const U&u) const
{
return t<u;
}
};
在您的代码中,您只需将其键入为 StringComparator
更新到评论
多索引来救援
如果您想将 std::map
/boost::container::map
替换为 Boost Multi Index 容器(支持通过 CompatibleKey 查找)
),这里是如何做到这一点的演示:
我从文档部分借用了一些想法 Emulating standard containers with multi_index_container
。
请注意,std::string
作为查找键仍然不起作用,但您可以在该事件中轻松使用 .c_strio()
。
#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>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/member.hpp>
namespace emulation {
template <typename T1,typename T2,typename Alloc>
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<T1,T2>& p):first(p.first),second(p.second){}
T1 first;
mutable T2 second;
};
using namespace boost::multi_index;
template <typename Key, typename T, typename Compare, typename Allocator, typename Element = mutable_pair<Key, T, Allocator> >
using map = multi_index_container<
Element,
indexed_by<
ordered_unique<member<Element,Key,&Element::first>,Compare>
>,
typename Allocator::template rebind<Element>::other
>;
template <typename Key, typename T, typename Compare, typename Allocator, typename Element = mutable_pair<Key, T, Allocator> >
using multimap = multi_index_container<
Element,
indexed_by<
ordered_non_unique<member<Element,Key,&Element::first>,Compare>
>,
typename Allocator::template rebind<Element>::other
>;
template <typename Key, typename T, typename Compare, typename Allocator>
struct wrap_map : map<Key, T, Compare, Allocator> {
typedef map<Key, T, Compare, Allocator> 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<void, SegmentManager> Allocator;
typedef boost::interprocess::allocator<char, SegmentManager> CharAllocator;
typedef boost::interprocess::basic_string<char, std::char_traits<char>, CharAllocator> String;
struct MyLess {
template <typename T, typename U> bool operator()(const T &t, const U &u) const { return t < u; }
};
typedef MyLess StringComparator;
typedef boost::interprocess::allocator<char, SegmentManager> StringAlloc;
typedef emulation::mutable_pair<const String, String, StringAlloc> MapItem;
typedef boost::interprocess::allocator<MapItem, SegmentManager> MapItemAllocator;
typedef emulation::wrap_map<String, String, StringComparator, MapItemAllocator> 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<Shared::Map>("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;
}
打印:
Found: 'foo' -> 'bar'
Found: 'foo' -> 'bar'
Found: 'foo' -> 'bar'
作用域分配器是否可以提供额外的 Awesomesauce?
现在,有趣的是,Boost Container 支持作用域分配器,因此您可以消除分配器的重复传递,但是遗憾的是,Boost Multi Index 并不完全支持它。这是我所能得到的一种折中方法(仍然对用户更友好):
#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>
#include <boost/container/scoped_allocator.hpp>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/member.hpp>
namespace emulation {
template <typename T1,typename T2,typename Alloc>
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<T1,T2>& p):first(p.first),second(p.second){}
template <typename U, typename V, typename Alloc2>
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 <typename Key, typename T, typename Compare, typename Allocator, typename Element = mutable_pair<Key, T, Allocator> >
using map = multi_index_container<
Element,
indexed_by<
ordered_unique<member<Element,Key,&Element::first>,Compare>
>,
typename Allocator::template rebind<Element>::other
>;
template <typename Key, typename T, typename Compare, typename Allocator, typename Element = mutable_pair<Key, T, Allocator> >
using multimap = multi_index_container<
Element,
indexed_by<
ordered_non_unique<member<Element,Key,&Element::first>,Compare>
>,
typename Allocator::template rebind<Element>::other
>;
template <typename Key, typename T, typename Compare, typename Allocator>
struct wrap_map : map<Key, T, Compare, Allocator> {
typedef map<Key, T, Compare, Allocator> 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<boost::interprocess::allocator<void, SegmentManager> > Allocator;
typedef Allocator::rebind<char>::other CharAllocator;
typedef boost::interprocess::basic_string<char, std::char_traits<char>, CharAllocator> String;
struct MyLess {
template <typename T, typename U> bool operator()(const T &t, const U &u) const { return t < u; }
};
typedef MyLess StringComparator;
typedef emulation::mutable_pair<String, String, CharAllocator> MapItem;
typedef Allocator::rebind<MapItem>::other MapItemAllocator;
typedef emulation::wrap_map<String, String, StringComparator, MapItemAllocator> 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<Shared::Map>("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;
}
同时打印
Found: 'foo' -> 'bar'
Found: 'foo' -> 'bar'
Found: 'foo' -> 'bar'
关于c++ - 想要有效地克服 Boost.Interprocess 共享内存中映射中关键类型之间的不匹配,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27328835/