As an introduction, bind_allocator
and the completion token's internal allocator serve different purposes. I think it will become much clearer if I first address the questions in your post at face value:
-
I would like to know how I can bind an allocator to a custom token of mine [...]
It seems to me that bind_allocator
already does what you ask:
Live On Coliru
auto h = [](boost::system::error_code, size_t) {};
asio::streambuf b(1024);
std::allocator<char> a1;
pmr::polymorphic_allocator<char> a2{pmr::get_default_resource()};
async_read(s, b, h);
async_read(s, b, asio::bind_allocator(a1, h));
async_read(s, b, asio::bind_allocator(a2, h));
async_read(s, b, asio::use_future);
async_read(s, b, asio::bind_allocator(a1, asio::use_future));
async_read(s, b, asio::bind_allocator(a2, asio::use_future));
-
[...] and use it in the token's async_result implementation?
You query it with get_associated_allocator
.
-
But I don't see a path where that allocator is passed down to my my::use_future token in its async_result<>::initiate function.
That's because it isn't. bind_allocator(tok)
returns allocator_binder< typename decay< T >::type, Allocator >
. This then is the token type. Therefore any composing operations will "see" your bound associator type, but not your token internally.
How To Fix?
What you want is not merely an allocator associated with an allocator-agnostic completion token/handler. Rather you need an allocator-aware completion token.
You can create it like you would any classically allocator-aware type, e.g. for standard library types.
In fact, for example the asio::use_future
token type is actually defined as asio::use_future_t<std::allocator<void> >
.
As such it is both allocator-aware (the async_result
specialization can respond to the chosen allocator type), and implements the associated_allocator
protocol to provide Handler
semantics.
I feel that the associated_XXXX
protocol is closely inspired on the underused std::uses_allocator
protocol. I'm using my own term "protocol" here to communicate that, in addition to an explicit trait type, there's a convention that plays together with the trait's primary template. But I digress.
Side-note
Note that allocators are less strictly adhered to than say, bound executors. The latter are essential to program correctness. For allocators, the documentation states _"Implementers can ignore the allocator, especially if the operation is not considered performance-sensitive".