希望有效地克服 Boost.Process 间共享内存中映射中键类型之间的不匹配
want to efficiently overcome mismatch between key types in a map in Boost.Interprocess shared memory
我正在使用Boost.Interprocess在共享内存中创建映射(在本例中从字符串到字符串(。编译器似乎想强迫我在从地图检索期间在托管段只是(不必要地(包含查询词。
我希望能够通过将映射的键与已在非共享内存中的实例进行匹配,更高效地查找共享映射中的值,而无需执行此额外分配。 但它是如果我尝试使用 std::string
或 const char *
作为地图find
方法的参数,则拒绝编译。(请参阅底部的编译器错误消息(。
我需要定义某种我的共享内存密钥类型与其非共享等效项之间的比较器方法(在本例中std::string
(?如果是这样,应该怎么做这看起来像,我应该如何使地图使用它? 如果没有,我该怎么办?
下面是代码,后跟编译器错误。 问题出在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
为key
:
$ 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 *
为key
:
$ 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
查找(,下面是如何执行此操作的演示:
我从文档部分借用了一些想法 用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'
范围分配器以获得额外的真棒酱?
现在,有趣的是,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'
以下内容改编自@sehe对自己答案的评论链接的C++03兼容代码。 虽然我真的不知道我在做什么,但我通过向mutable_pair
和map_gen
定义添加第二个分配器类型,以似乎适合键与其映射值不属于同一类型的映射的方式对其进行了概括。 我已经明确了所有内容都来自哪个命名空间,并为简洁起见删除了multimap_gen
定义。 它编译以允许使用const char *
查询共享内存中的map< string vector<int> >
类型对象。
我不确定的一件事是ValueType
是否需要出现在rebind
行中,但它似乎可以像目前一样编译和工作......
#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 sehe
{
template < typename T1, typename T2, typename Alloc1, typename Alloc2 >
struct mutable_pair
{
typedef T1 first_type;
typedef T2 second_type;
mutable_pair( Alloc1 alloc1, Alloc2 alloc2 ) : first( T1( alloc1 ) ), second( T2( alloc2 ) ) {}
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;
};
template <typename KeyType, typename ValueType, typename Compare, typename KeyAllocator, typename ValueAllocator, typename Element = mutable_pair< KeyType, ValueType, KeyAllocator, ValueAllocator > >
struct map_gen
{
typedef boost::multi_index::multi_index_container
<
Element,
boost::multi_index::indexed_by
<
boost::multi_index::ordered_unique< boost::multi_index::member< Element, KeyType, &Element::first >, Compare >
>,
typename KeyAllocator::template rebind<Element>::other
> type;
};
typedef struct {
template <typename T, typename U> bool operator()(const T &t, const U &u) const { return t < u; }
} Comparator;
}
// 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> CharAlloc;
typedef boost::interprocess::basic_string<char, std::char_traits<char>, CharAlloc> String;
typedef boost::interprocess::allocator< String, SegmentManager > StringAlloc;
typedef boost::interprocess::allocator< int, SegmentManager > IntAlloc;
typedef boost::interprocess::vector< int, IntAlloc > IntVector;
typedef boost::interprocess::allocator< IntVector, SegmentManager > IntVectorAlloc;
typedef sehe::map_gen< String, String, sehe::Comparator, StringAlloc, StringAlloc >::type StringStringMap;
typedef sehe::map_gen< String, IntVector, sehe::Comparator, StringAlloc, IntVectorAlloc >::type StringIntVectorMap;
}
- 值到类型的运行时映射
- 拥有映射的现代方法,该映射可以指向或引用已在堆栈上分配的不同类型的数据
- 如何将高维数据映射到特征类型?
- 如何使映射键具有两种不同的数据类型?
- 值和类型的简洁双向静态 1:1 映射
- 当 map 是一个整数数组并且由 operator[] 创建时,它是否初始化其映射类型
- 编译按映射类型获取元素的映射错误元组
- 模板.参数包扩展 - 重映射类型
- C++函数来返回基于参数的比较器通用映射类型?
- ATL ActiveX DLL 作为映射类型图像和数据加载了两次
- 如何在 C++ 中获取映射类型指针,映射
- 映射类型为的队列容器
- 如何使用boost::mutex作为std::map中的映射类型
- 正向声明映射的映射类型和C++11
- std::map何时调用映射类型的构造函数
- 基于映射类型c++解析和转换csv
- 模板类的映射类型签名(声明)
- c++映射类型的属性
- 使用映射类型会产生GCC错误:预期的未限定id在' for '之前
- 在 EIGEN 中单独声明和初始化映射类型矩阵