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

如何将分配器绑定到自定义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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 12:25:30