I am reading implementation of asio handlers using custom allocators. manual
I am trying to implement my own custom allocator using pmr. But fails in compilation with the following error
prog.cc: In instantiation of
'AsioHandler<Handler>::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 '<brace-enclosed initializer list>' 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<void>, 0>&; U = AsioHandler<main()::<lambda()> >; T = AsioHandler<main()::<lambda()> >; Executor = boost::asio::io_context::basic_executor_type<std::allocator<void>, 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<void>, 0>; executor_type = boost::asio::io_context::basic_executor_type<std::allocator<void>, 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<void>, 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();
}
How to fix this?
That's... a lot of code. It has a ton of unused headers, unnecessary threads, a duplicated
Handler h_member which is already a base class (!), the invalidforward<>on a non-deduced rvalue reference, missingallocator_typetypedef, questionabledo_is_equalimplementation, usingremove_reference_tinstead ofdecay_t, etc.Next up, your
memory_resourcesubclass shadowsbc::pmr::memory_resourcemaking your code hard to grok. E.g., which did you mean to use forAsioHandler::alloc_? I'd assume your own (let's call itmy_memory_resourcefor now), but the initializer isn't compatible at all. Did you meanmy_memory_resourceinstead ofmy_memory_resource*?Regardless of everything,
pool_being of typebc::pmc::monotonic_buffer_resourcemakesAsioHandlernon-copyable by definition.All this combined really makes me scratch my head how you even got the compiler message you posted in the first place.
I can make your code compile by fixing the non-copyability (making AsioHandler move-only), but I will not vouch for this code to be useful:
Live On Coliru
Prints