В моем текущем проекте я храню некоторые данные в unordered_map
в общей памяти, используя библиотеку Boost Interprocess.Вот минимальный пример:
#include <unordered_map>
#include <atomic>
#include <iostream>
#include <iterator>
#include <utility>
#include <string>
#include <scoped_allocator>
#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
namespace ipc = boost::interprocess;
struct Foo {
Foo(size_t _a){
a = _a;
}
size_t a;
std::atomic<bool> deleted {false};
};
/**
* allocator type needed to construct maps in shared memory
*/
template <typename OBJ_T>
using OBJ_ALLOC = ipc::allocator<std::pair<const size_t, OBJ_T>,
ipc::managed_shared_memory::segment_manager>;
/**
* map type to construct maps in shared memory. ideally, only construct the content in-place
* to avoid excessive copying ...
*/
template <typename OBJ_T>
using OBJ_MAP = std::unordered_map<size_t,
OBJ_T,
std::hash<size_t>,
std::equal_to<size_t>,
std::scoped_allocator_adaptor<OBJ_ALLOC<OBJ_T>>>;
int main(){
OBJ_MAP<Foo> *map;
ipc::managed_shared_memory data_segment(ipc::open_or_create,
std::string("data_segment").c_str(),
4096);
OBJ_ALLOC<Foo> alloc(data_segment.get_segment_manager());
map = data_segment.find_or_construct<OBJ_MAP<Foo>>
(ipc::unique_instance)
(alloc);
map->emplace(std::piecewise_construct,
std::forward_as_tuple(1),
std::forward_as_tuple(2321));
// before
for(auto it = map->begin(); it != map->end(); it++) {
std::cout << "Key: " << it->first << " Value: " << it->second.a << std::endl;
}
auto i = map->extract(1);
i.key() = 2;
map->insert(std::move(i));
// after
for(auto it = map->begin(); it != map->end(); it++) {
std::cout << "Key: " << it->first << " Value: " << it->second.a << std::endl;
}
data_segment.destroy<OBJ_MAP<Foo>>(ipc::unique_instance);
ipc::shared_memory_object::remove(std::string("data_segment").c_str());
return 0;
}
Первоначально я разработал проект для MacOS, поэтому я скомпилировал для clang ++ / libc ++ 7.0.0, который прекрасно работает.
clang++ test_map.cpp -std=c++17 -stdlib=libc++ -lpthread -lrt
Теперь яm переносит все это на Linux и получает ошибки с g ++ и libstdc ++ (g ++ 8.2.1).
g++ test_map.cpp -std=c++17 -lpthread -lrt
Извлечение узла не компилируется из-за неявно удаленного конструктора копии, и-insertion не удается из-за некоторого нежизнеспособного преобразования, но сообщения об ошибках очень загадочные.
Он отлично работает с clang ++ / libc ++ в linux, но это означает, что все зависимые библиотеки, такие как Boost, должны быть скомпилированыс тем же набором инструментов, что довольно хлопотно.
Как объяснить эти различия и есть ли способ их обойти?
РЕДАКТИРОВАТЬ : вот код: https://gcc.godbolt.org/z/L40Jsl
РЕДАКТИРОВАТЬ : и фактическое сообщение об ошибке ...
user@computer ~/repos/playground % g++ -std=c++17 test_map.cpp
In file included from /usr/include/c++/8.2.1/unordered_map:46,
from test_map.cpp:1:
/usr/include/c++/8.2.1/bits/hashtable.h: In instantiation of ‘std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::insert_return_type
std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::_M_reinsert_node(std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1,
_H2, _Hash, _RehashPolicy, _Traits>::node_type&&) [with _Key = long unsigned int; _Value = std::pair<const long unsigned int, Foo>; _Alloc = std::scoped_allocator_adaptor<boost::inte
rprocess::allocator<std::pair<const long unsigned int, Foo>, boost::interprocess::segment_manager<char, boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family>, boost
::interprocess::iset_index> > >; _ExtractKey = std::__detail::_Select1st; _Equal = std::equal_to<long unsigned int>; _H1 = std::hash<long unsigned int>; _H2 = std::__detail::_Mod_ran
ge_hashing; _Hash = std::__detail::_Default_ranged_hash; _RehashPolicy = std::__detail::_Prime_rehash_policy; _Traits = std::__detail::_Hashtable_traits<false, false, true>; std::_Ha
shtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::insert_return_type = std::_Node_insert_return<std::__detail::_Node_iterator<std::pair<con
st long unsigned int, Foo>, false, false>, std::_Node_handle<long unsigned int, std::pair<const long unsigned int, Foo>, std::scoped_allocator_adaptor<boost::interprocess::allocator<
std::__detail::_Hash_node<std::pair<const long unsigned int, Foo>, false>, boost::interprocess::segment_manager<char, boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_
family>, boost::interprocess::iset_index> > > > >; typename std::__allocator_traits_base::__rebind<_Alloc, std::__detail::_Hash_node<_Value, typename _Traits::__hash_cached::value>,
void>::type = std::scoped_allocator_adaptor<boost::interprocess::allocator<std::__detail::_Hash_node<std::pair<const long unsigned int, Foo>, false>, boost::interprocess::segment_man
ager<char, boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family>, boost::interprocess::iset_index> > >; typename std::__detail::_Hashtable_base<_Key, _Value, _Extra
ctKey, _Equal, _H1, _H2, _Hash, _Traits>::iterator = std::__detail::_Node_iterator<std::pair<const long unsigned int, Foo>, false, false>; std::_Hashtable<_Key, _Value, _Alloc, _Extr
actKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::node_type = std::_Node_handle<long unsigned int, std::pair<const long unsigned int, Foo>, std::scoped_allocator_adaptor<boos
t::interprocess::allocator<std::__detail::_Hash_node<std::pair<const long unsigned int, Foo>, false>, boost::interprocess::segment_manager<char, boost::interprocess::rbtree_best_fit<
boost::interprocess::mutex_family>, boost::interprocess::iset_index> > > >]’:
/usr/include/c++/8.2.1/bits/unordered_map.h:438:53: required from ‘std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::insert_return_type std::unordered_map<_Key, _Tp, _Hash, _Pre
d, _Alloc>::insert(std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::node_type&&) [with _Key = long unsigned int; _Tp = Foo; _Hash = std::hash<long unsigned int>; _Pred = std::equ
al_to<long unsigned int>; _Alloc = std::scoped_allocator_adaptor<boost::interprocess::allocator<std::pair<const long unsigned int, Foo>, boost::interprocess::segment_manager<char, bo
ost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family>, boost::interprocess::iset_index> > >; std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::insert_return_type =
std::_Node_insert_return<std::__detail::_Node_iterator<std::pair<const long unsigned int, Foo>, false, false>, std::_Node_handle<long unsigned int, std::pair<const long unsigned int
, Foo>, std::scoped_allocator_adaptor<boost::interprocess::allocator<std::__detail::_Hash_node<std::pair<const long unsigned int, Foo>, false>, boost::interprocess::segment_manager<c
har, boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family>, boost::interprocess::iset_index> > > > >; std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::node_type
= std::_Node_handle<long unsigned int, std::pair<const long unsigned int, Foo>, std::scoped_allocator_adaptor<boost::interprocess::allocator<std::__detail::_Hash_node<std::pair<cons
t long unsigned int, Foo>, false>, boost::interprocess::segment_manager<char, boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family>, boost::interprocess::iset_index
> > > >]’
test_map.cpp:63:27: required from here
/usr/include/c++/8.2.1/bits/hashtable.h:809:5: error: no matching function for call to ‘std::_Hashtable<long unsigned int, std::pair<const long unsigned int, Foo>, std::scoped_alloca
tor_adaptor<boost::interprocess::allocator<std::pair<const long unsigned int, Foo>, boost::interprocess::segment_manager<char, boost::interprocess::rbtree_best_fit<boost::interproces
s::mutex_family>, boost::interprocess::iset_index> > >, std::__detail::_Select1st, std::equal_to<long unsigned int>, std::hash<long unsigned int>, std::__detail::_Mod_range_hashing,
std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, std::__detail::_Hashtable_traits<false, false, true> >::_M_insert_unique_node(std::_Hashtable<long unsigned
int, std::pair<const long unsigned int, Foo>, std::scoped_allocator_adaptor<boost::interprocess::allocator<std::pair<const long unsigned int, Foo>, boost::interprocess::segment_manag
er<char, boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family>, boost::interprocess::iset_index> > >, std::__detail::_Select1st, std::equal_to<long unsigned int>, s
td::hash<long unsigned int>, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, std::__detail::_Hashtable_traits<false, fals
e, true> >::size_type&, std::_Hashtable<long unsigned int, std::pair<const long unsigned int, Foo>, std::scoped_allocator_adaptor<boost::interprocess::allocator<std::pair<const long
unsigned int, Foo>, boost::interprocess::segment_manager<char, boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family>, boost::interprocess::iset_index> > >, std::__d
etail::_Select1st, std::equal_to<long unsigned int>, std::hash<long unsigned int>, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehas
h_policy, std::__detail::_Hashtable_traits<false, false, true> >::__hash_code&, std::allocator_traits<std::scoped_allocator_adaptor<boost::interprocess::allocator<std::__detail::_Has
h_node<std::pair<const long unsigned int, Foo>, false>, boost::interprocess::segment_manager<char, boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family>, boost::int
erprocess::iset_index> > > >::pointer&)’
= _M_insert_unique_node(__bkt, __code, __nh._M_ptr);
/usr/include/c++/8.2.1/bits/hashtable.h:1717:5: note: candidate: ‘std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::iterator std::_
Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::_M_insert_unique_node(std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _
H2, _Hash, _RehashPolicy, _Traits>::size_type, std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::__hash_code, std::_Hashtable<_Key,
_Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::__node_type*, std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolic
y, _Traits>::size_type) [with _Key = long unsigned int; _Value = std::pair<const long unsigned int, Foo>; _Alloc = std::scoped_allocator_adaptor<boost::interprocess::allocator<std::p
air<const long unsigned int, Foo>, boost::interprocess::segment_manager<char, boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family>, boost::interprocess::iset_index
> > >; _ExtractKey = std::__detail::_Select1st; _Equal = std::equal_to<long unsigned int>; _H1 = std::hash<long unsigned int>; _H2 = std::__detail::_Mod_range_hashing; _Hash = std::_
_detail::_Default_ranged_hash; _RehashPolicy = std::__detail::_Prime_rehash_policy; _Traits = std::__detail::_Hashtable_traits<false, false, true>; std::_Hashtable<_Key, _Value, _All
oc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::iterator = std::__detail::_Node_iterator<std::pair<const long unsigned int, Foo>, false, false>; std::_Hashtable<_K
ey, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::size_type = long unsigned int; std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2,
_Hash, _RehashPolicy, _Traits>::__hash_code = long unsigned int; std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::__node_type = s
td::__detail::_Hash_node<std::pair<const long unsigned int, Foo>, false>; typename _Traits::__hash_cached = std::integral_constant<bool, false>]’
_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
_H1, _H2, _Hash, _RehashPolicy, _Traits>::
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/c++/8.2.1/bits/hashtable.h:1717:5: note: no known conversion for argument 3 from ‘std::allocator_traits<std::scoped_allocator_adaptor<boost::interprocess::allocator<st
d::__detail::_Hash_node<std::pair<const long unsigned int, Foo>, false>, boost::interprocess::segment_manager<char, boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_fa
mily>, boost::interprocess::iset_index> > > >::pointer’ {aka ‘boost::interprocess::offset_ptr<std::__detail::_Hash_node<std::pair<const long unsigned int, Foo>, false>, long int, lon
g unsigned int, 0>’} to ‘std::_Hashtable<long unsigned int, std::pair<const long unsigned int, Foo>, std::scoped_allocator_adaptor<boost::interprocess::allocator<std::pair<const long
unsigned int, Foo>, boost::interprocess::segment_manager<char, boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family>, boost::interprocess::iset_index> > >, std::__
detail::_Select1st, std::equal_to<long unsigned int>, std::hash<long unsigned int>, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_reha
sh_policy, std::__detail::_Hashtable_traits<false, false, true> >::__node_type*’ {aka ‘std::__detail::_Hash_node<std::pair<const long unsigned int, Foo>, false>*’}