如何解决C++ 放置新的与 boost 分配器不兼容
我正在使用 Boost.Interprocess 共享内存,并且我正在将进程间分配器与一些 STL 兼容容器一起使用,当涉及到 placement new
时,代码将无法编译,因为placement new
期望 void *
而 boost::interprocess::allocator::pointer
不能转换为 void *
。
下面是重现这个的代码
#include <memory>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/managed_shared_memory.hpp>
namespace ipc = boost::interprocess;
typedef ipc::allocator<int,ipc::managed_shared_memory::segment_manager> ShmemAllocator;
int main() {
struct shm_remove {
shm_remove() { ipc::shared_memory_object::remove("MySharedMemory"); }
~shm_remove() { ipc::shared_memory_object::remove("MySharedMemory"); }
} remover;
ipc::managed_shared_memory segment(ipc::open_or_create,"MySharedMemory",1024 * 1024 * 10);
ShmemAllocator shm_alloc(segment.get_segment_manager());
ShmemAllocator::pointer shm_ptr = shm_alloc.allocate(1);
std::allocator<int> std_alloc;
std::allocator<int>::pointer std_ptr = std_alloc.allocate(1);
new(std_ptr) int(3);
new(shm_ptr) int(3); // this line doesn't work
return 0;
}
我得到的编译错误:
/home/ziqi.liu/ClionProjects/shared_memory_experiment/src/main_a.cpp: In function ‘int main()’:
/home/ziqi.liu/ClionProjects/shared_memory_experiment/src/main_a.cpp:22:21: error: no matching function for call to ‘operator new(sizetype,boost::interprocess::allocator<int,boost::interprocess::segment_manager<char,boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family>,boost::interprocess::iset_index> >::pointer&)’
new(shm_ptr) int(3); // this line doesn't work
^
In file included from /usr/include/c++/5/ext/new_allocator.h:33:0,from /usr/include/x86_64-linux-gnu/c++/5/bits/c++allocator.h:33,from /usr/include/c++/5/bits/allocator.h:46,from /usr/include/c++/5/memory:63,from /home/ziqi.liu/ClionProjects/shared_memory_experiment/src/main_a.cpp:1:
/usr/include/c++/5/new:111:7: note: candidate: void* operator new(std::size_t)
void* operator new(std::size_t) _GLIBCXX_THROW (std::bad_alloc)
^
/usr/include/c++/5/new:111:7: note: candidate expects 1 argument,2 provided
/usr/include/c++/5/new:119:7: note: candidate: void* operator new(std::size_t,const std::nothrow_t&)
void* operator new(std::size_t,const std::nothrow_t&) _GLIBCXX_USE_NOEXCEPT
^
/usr/include/c++/5/new:119:7: note: no kNown conversion for argument 2 from ‘boost::interprocess::allocator<int,boost::interprocess::iset_index> >::pointer {aka boost::interprocess::offset_ptr<int,long int,long unsigned int,0ul>}’ to ‘const std::nothrow_t&’
/usr/include/c++/5/new:129:14: note: candidate: void* operator new(std::size_t,void*)
inline void* operator new(std::size_t,void* __p) _GLIBCXX_USE_NOEXCEPT
^
/usr/include/c++/5/new:129:14: note: no kNown conversion for argument 2 from ‘boost::interprocess::allocator<int,0ul>}’ to ‘void*’
In file included from /home/ziqi.liu/.tspkg/include/boost/interprocess/mem_algo/detail/mem_algo_common.hpp:35:0,from /home/ziqi.liu/.tspkg/include/boost/interprocess/allocators/detail/allocator_common.hpp:35,from /home/ziqi.liu/.tspkg/include/boost/interprocess/allocators/allocator.hpp:30,from /home/ziqi.liu/ClionProjects/shared_memory_experiment/src/main_a.cpp:2:
/home/ziqi.liu/.tspkg/include/boost/container/detail/placement_new.hpp:24:14: note: candidate: void* operator new(std::size_t,void*,boost_container_new_t)
inline void *operator new(std::size_t,void *p,boost_container_new_t)
^
/home/ziqi.liu/.tspkg/include/boost/container/detail/placement_new.hpp:24:14: note: candidate expects 3 arguments,2 provided
CMakeFiles/main_a.dir/build.make:62: recipe for target 'CMakeFiles/main_a.dir/src/main_a.cpp.o' Failed
make[2]: *** [CMakeFiles/main_a.dir/src/main_a.cpp.o] Error 1
CMakeFiles/Makefile2:162: recipe for target 'CMakeFiles/main_a.dir/all' Failed
make[1]: *** [CMakeFiles/main_a.dir/all] Error 2
Makefile:83: recipe for target 'all' Failed
make: *** [all] Error 2
我确定一定有办法做到这一点,因为 boost 自己的容器都与 boost::interprocess::allocator::pointer
兼容,但我不确定他们是怎么做到的......我想我应该看看新版位的替代方案?
解决方法
在容器中使用分配器时,构造对象的正确方法是调用
myclass2
请参阅 CppReference 了解更多信息。
如果您需要 C++03 解决方案(C++03 中没有 std::allocator_traits<AllocatorType>::construct(alloc,pointer,...constructor parameters...)
),那么您可以直接调用分配器 allocator_traits
方法 - 但这不是推荐的解决方案。
你说得对,标准容器不提供花哨的指针。参见例如
-
https://en.cppreference.com/w/cpp/named_req/Allocator#Fancy_pointers:
花式指针的一个例子是映射地址无关 指针 boost::interprocess::offset_ptr,这使得 在共享内存中分配基于节点的数据结构,例如 std::set 和内存映射文件映射在每个不同的地址 过程。花式指针可以独立于分配器使用 通过类模板 std::pointer_traits 提供它们 (从 C++11 开始)。函数 std::to_address 可用于获取 来自花式指针的原始指针。 (C++20 起)
我通常会选择使用 Boost Container 集合,因为它们确实支持这些。而且,根据我的经验,它们在作用域分配器适配器上的表现似乎比大多数标准库实现要好得多。
只是为了偷懒:
#include <boost/container/container_fwd.hpp>
#include <boost/container/scoped_allocator_fwd.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/managed_mapped_file.hpp>
#include <boost/container/vector.hpp>
#include <boost/container/map.hpp>
#include <boost/container/string.hpp>
#include <boost/container/scoped_allocator.hpp>
#include <functional>
#include <memory>
namespace ipc = boost::interprocess;
namespace bc = boost::container;
template <typename T>
using Alloc = ipc::allocator<T,ipc::managed_mapped_file::segment_manager>;
template <typename T>
using ScopedAlloc = bc::scoped_allocator_adaptor<Alloc<T> >;
template <typename T>
using SharedVector = bc::vector<T,Alloc<T> >;
template <typename K,typename V,typename Pair = std::pair<K const,V> >
using SharedMap = bc::map<K,V,std::less<>,ScopedAlloc<Pair> >;
int main() {
ipc::managed_mapped_file segment(ipc::open_or_create,"MySharedMemory",1024 * 100);
auto* sm = segment.get_segment_manager();
{
auto &v = *segment.find_or_construct<SharedVector<int>>("vector")(sm);
v.push_back(3);
v.insert(v.begin(),5);
v.emplace_back(16);
}
{
using String = bc::basic_string<char,std::char_traits<char>,ScopedAlloc<char> >;
auto &m = *segment.find_or_construct<SharedMap<String,String> >("map")(sm);
m.emplace("whoa","not bad");
m.emplace("at","all");
}
}
请注意,由于 Coliru 的限制,我使用了较小的尺寸和 managed_mapped_file
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。