You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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 |
memory_resource * alloc
{&pool
};
| ^~~~~~
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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 01:07:06