如何将分配器绑定到自定义token并在async_result中使用?
绑定分配器到自定义Token并在async_result中使用
核心方案:适配bind_allocator的包装特性
Boost.Asio的bind_allocator会把分配器和目标token包装成asio::bind_allocator_t<Allocator, Token>类型。要让自定义token(比如你的my::use_future)能拿到这个分配器,需要针对这个包装类型特化async_result,或者让原token的async_result支持提取分配器。
步骤1:为包装后的Token特化async_result
直接针对bind_allocator_t包装后的my::use_future_t写async_result特化,就能在initiate函数里直接拿到绑定的分配器:
namespace my { struct use_future_t {}; constexpr use_future_t use_future{}; // 针对bind_allocator包装后的token的async_result特化 template <typename Allocator, typename Signature> struct async_result<asio::bind_allocator_t<Allocator, use_future_t>, Signature> { // 定义结果类型和带分配器的future类型 using result_type = std::invoke_result_t<Signature>; using future_type = my::future<result_type, Allocator>; template <typename Initiation, typename... Args> static future_type initiate( Initiation&& init, asio::bind_allocator_t<Allocator, use_future_t> token, Args&&... args ) { // 提取绑定的分配器 auto alloc = token.get_allocator(); // 创建带分配器的future实例 future_type fut(alloc); // 发起异步操作,传递自定义完成回调 std::forward<Initiation>(init)( [fut = std::move(fut), alloc](auto... res) mutable { // 使用绑定的分配器构造结果 std::allocator_traits<Allocator>::construct( alloc, &fut.result_, std::forward<decltype(res)>(res)... ); fut.set_value(); }, std::forward<Args>(args)... ); return fut; } }; // 原token的默认async_result(适配未绑定分配器的场景) template <typename Signature> struct async_result<use_future_t, Signature> { using future_type = my::future<std::invoke_result_t<Signature>>; template <typename Initiation, typename... Args> static future_type initiate(Initiation&& init, use_future_t, Args&&... args) { future_type fut; std::forward<Initiation>(init)( [fut = std::move(fut)](auto... res) mutable { fut.set_value(std::forward<decltype(res)>(res)...); }, std::forward<Args>(args)... ); return fut; } }; } // namespace my
步骤2:让自定义Future支持分配器
确保你的my::future类型提供带分配器参数的构造函数,适配内存分配需求:
namespace my { template <typename T, typename Allocator = std::allocator<T>> class future { public: explicit future(const Allocator& alloc = Allocator()) : alloc_(alloc) {} // 暴露内部结果存储的指针供构造使用(示例) T* result_ptr() { return &result_.emplace(); } void set_value() { /* 唤醒等待的线程逻辑 */ } private: Allocator alloc_; std::optional<T> result_; // 同步原语(如std::mutex、std::condition_variable) }; } // namespace my
关于use_tuple的局限性
use_tuple的设计是通过自身的rebind方法关联分配器,它的async_result依赖token内部存储的分配器来构造tuple。而我们的方案通过适配bind_allocator的包装类型,让分配器由外部注入,不需要token自身携带分配器状态,灵活性更高。
验证代码
现在你可以直接使用目标代码:
async_read(socket, buffer, bind_allocator(some_polymorphic_alloc, my::use_future));
Asio会自动匹配到bind_allocator_t对应的async_result特化,initiate函数里就能拿到some_polymorphic_alloc并用于future的内存分配。
内容的提问来源于stack exchange,提问作者Johannes Schaub - litb
相关产品推荐
相关产品推荐

