使用Asio与PMR自定义分配器实现异步投递编译错误修复求助
我正在学习Asio handler自定义分配器的实现,参考官方手册尝试用PMR实现自定义分配器,但编译失败,报错信息如下:
prog.cc: In instantiation of
'AsioHandler::AsioHandler(Handler&&) [with Handler = main()::<lambda()>]':
prog.cc:77:35: required from 'AsioHandler<typename std::remove_reference<Tp>::type> make_custom_alloc_handler(Handler&&) [with Handler = main()::<lambda()>; typename std::remove_reference<Tp>::type =
main()::<lambda()>]'
prog.cc:84:55: required from here
prog.cc:69:24: error: cannot convert '' to 'memory_resource*' in initialization 69 | {&pool};
memory_resource * alloc
| ^~~~~~
In file included from /opt/wandbox/boost-1.81.0-gcc-12.2.0/include/boost/asio.hpp:52,
from prog.cc:13: /opt/wandbox/boost-1.81.0-gcc-12.2.0/include/boost/asio/bind_executor.hpp:
In instantiation of 'boost::asio::detail::executor_binder_base<T, Executor, false>::executor_binder_base(E&&, U&&) [with E = const boost::asio::io_context::basic_executor_type<std::allocator, 0>&; U = AsioHandler<main()::<lambda()> >; T = AsioHandler<main()::<lambda()> >; Executor = boost::asio::io_context::basic_executor_type<std::allocator , 0>]':
/opt/wandbox/boost-1.81.0-gcc-12.2.0/include/boost/asio/bind_executor.hpp:295:46: required from 'boost::asio::executor_binder<T, Executor>::executor_binder(boost::asio::executor_arg_t, const executor_type&, U&&) [with U = AsioHandler<main()::<lambda()> >; T = AsioHandler<main()::<lambda()> >; Executor = boost::asio::io_context::basic_executor_type<std::allocator, 0>; executor_type = boost::asio::io_context::basic_executor_type<std::allocator , 0>]'
/opt/wandbox/boost-1.81.0-gcc-12.2.0/include/boost/asio/bind_executor.hpp:508:10: required from 'boost::asio::executor_binder<typename std::decay<_Tp2>::type, typename ExecutionContext::executor_type> boost::asio::bind_executor(ExecutionContext&, T&&, typename constraint<std::is_convertible<ExecutionContext&, execution_context&>::value>::type) [with ExecutionContext = io_context; T = AsioHandler<main()::<lambda()> >; typename ExecutionContext::executor_type = io_context::basic_executor_type<std::allocator, 0>; typename std::decay<_Tp2>::type = std::decay<AsioHandler<main()::<lambda()> > ::type; typename constraint<std::is_convertible<ExecutionContext&, execution_context&>::value>::type = int]'
prog.cc:86:49: required from here
/opt/wandbox/boost-1.81.0-gcc-12.2.0/include/boost/asio/bind_executor.hpp:181:7: error: call of overloaded 'AsioHandler(AsioHandler<main()::<lambda()> >)' is ambiguous
相关实现代码如下:
#include <boost/container/pmr/monotonic_buffer_resource.hpp> #include <boost/container/pmr/global_resource.hpp> #include <cstdlib> #include <iostream> #include <thread> #include <boost/aligned_storage.hpp> #include <boost/array.hpp> #include <boost/bind.hpp> #include <boost/enable_shared_from_this.hpp> #include <boost/noncopyable.hpp> #include <boost/shared_ptr.hpp> #include <boost/asio.hpp> #include <boost/asio/post.hpp> namespace bc = boost::container; class memory_resource: public bc::pmr::memory_resource { public: explicit memory_resource(bc::pmr::memory_resource* up = bc::pmr::get_default_resource()) :upstream_(up){} void* do_allocate(size_t bytes, size_t alignment) override { void* ret = upstream_->allocate(bytes, alignment); return ret; } void do_deallocate(void* ptr, size_t bytes, size_t alignment) override { upstream_->deallocate(ptr, bytes, alignment); } bool do_is_equal(const bc::pmr::memory_resource& other) const noexcept override { return this == &other; } private: bc::pmr::memory_resource* upstream_; }; //template<typename Handler,size_t S = 2048> constexpr std::size_t S = 2048 ; template<typename Handler> class AsioHandler: public Handler { public: using Handler::operator(); AsioHandler(Handler && h) :h_(std::forward<Handler>(h)) { } memory_resource * get_allocator() const noexcept { return alloc_; } friend void* asio_handler_allocate(std::size_t size ,AsioHandler<Handler>* this_handler) { return this_handler->alloc_->do_allocate(size,S); } friend void asio_handler_deallocate(void* pointer, std::size_t size ,AsioHandler<Handler>* this_handler) { this_handler->alloc_->do_deallocate(pointer,size,S); } private: Handler h_; typename std::aligned_storage<S>::type storage_; boost::container::pmr::monotonic_buffer_resource pool_{&storage_,S}; memory_resource * alloc_{&pool_}; }; // Helper function to wrap a handler object to add custom allocation. template <typename Handler> AsioHandler<typename std::remove_reference<Handler>::type> make_custom_alloc_handler(Handler && h) { return {std::forward<Handler>(h)}; } int main() { boost::asio::io_context ctx; auto func = [](){}; auto h = make_custom_alloc_handler<decltype(func)>(std::move(func)); boost::asio::post(boost::asio::bind_executor(ctx, std::move(h))); std::thread t {[&ctx]() { ctx.run(); } }; t.join(); }
请问该如何修复这些编译错误?
1. 修复memory_resource*类型转换错误
第一处错误的核心是:你自定义的memory_resource类和Boost PMR库的monotonic_buffer_resource是两个独立类型,后者继承自bc::pmr::memory_resource,但并非你自定义类的子类,因此&pool_(monotonic_buffer_resource*类型)无法直接赋值给memory_resource*。
解决方式:
- 由于自定义的
memory_resource仅做上游资源的调用转发,无额外逻辑,可直接删除该类,改用bc::pmr::memory_resource*作为alloc_的类型。 - 同时修改
asio_handler_allocate和asio_handler_deallocate的实现,调用PMR资源的公开接口allocate/deallocate,而非do_allocate/do_deallocate(后者是保护成员)。
2. 修复构造函数调用歧义问题
第二处错误是因为AsioHandler继承了Handler,同时内部又持有Handler h_,导致编译器在移动构造时无法区分是调用继承带来的隐式构造,还是你自定义的移动构造函数。
解决方式:
- 删除
AsioHandler对Handler的继承,仅通过内部成员h_持有handler对象。 - 手动实现
operator(),将调用转发给h_,保证handler的执行逻辑正常触发。
完整修复后的代码示例
#include <boost/container/pmr/monotonic_buffer_resource.hpp> #include <boost/container/pmr/global_resource.hpp> #include <cstdlib> #include <iostream> #include <thread> #include <boost/aligned_storage.hpp> #include <boost/asio.hpp> #include <boost/asio/post.hpp> namespace bc = boost::container; constexpr std::size_t S = 2048; template<typename Handler> class AsioHandler { public: AsioHandler(Handler&& h) : h_(std::forward<Handler>(h)) {} void operator()() { h_(); } friend void* asio_handler_allocate(std::size_t size, AsioHandler<Handler>* this_handler) { return this_handler->alloc_->allocate(size, S); } friend void asio_handler_deallocate(void* pointer, std::size_t size, AsioHandler<Handler>* this_handler) { this_handler->alloc_->deallocate(pointer, size, S); } private: Handler h_; typename std::aligned_storage<S>::type storage_; bc::pmr::monotonic_buffer_resource pool_{&storage_, S}; bc::pmr::memory_resource* alloc_{&pool_}; }; template <typename Handler> AsioHandler<typename std::remove_reference<Handler>::type> make_custom_alloc_handler(Handler&& h) { return {std::forward<Handler>(h)}; } int main() { boost::asio::io_context ctx; auto func = [](){}; auto h = make_custom_alloc_handler(std::move(func)); boost::asio::post(boost::asio::bind_executor(ctx, std::move(h))); std::thread t{[&ctx]() { ctx.run(); }}; t.join(); }
内容的提问来源于stack exchange,提问作者getsoubl

