xto*_*ofl 11 c++ boost boost-asio move-semantics
根据http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/Handler.html,提供的处理程序io_service::post必须是可复制的.
但是,这排除了接受套接字的情况,并且移动了响应处理程序,从而保证作业只有一个处理程序:
auto socket = std::make_unique<socket>();
accepter.accept(*socket);
service.post([s{std::move(socket)}] {
asio::write(*s, buffer("response"), ignored_err);
});
Run Code Online (Sandbox Code Playgroud)
那么为什么这个可复制的构造要求呢?
- 编辑 -
澄清:我想让我的代码确保只存在一个处理程序实例.这使得理由更容易.
对于很多程序来说,CopyConstructible的要求太严格了,MoveConstructible更合适.
auto i = std::make_unique<int>();
auto handler_w_resource = [i{std::move(i)}]{ ++(*i);};
// auto copied = handler_w_resource; --> +1: lambda can't be copied!
auto moved = std::move(handler_w_resource);
Run Code Online (Sandbox Code Playgroud)
因此我很惊讶它无法移动:
service.post(std::move(moved)); // :( post accepts no rvalue
Run Code Online (Sandbox Code Playgroud)
我无法确定任何解释为什么需要处理程序的推理的材料CopyConstructible,但即使存在C++ 11支持,也会明确指出.该移动式处理程序的文档说明:
作为优化,用户定义的完成处理程序可以提供移动构造函数,Boost.Asio的实现将使用处理程序的移动构造函数而不是其复制构造函数.在某些情况下,Boost.Asio可能能够消除对处理程序的复制构造函数的所有调用.但是,处理程序类型仍然需要是可复制构造的.
当不满足类型要求时,Asio执行的类型检查允许更友好的编译器错误消息.此类型检查在调用堆栈中较早发生,并且不基于对象的使用是否会生成编译器错误.例如,当启用类型检查时,类型检查将为没有复制构造函数的处理程序发出编译器错误,即使已经消除了对处理程序的复制构造函数的所有调用.通过定义BOOST_ASIO_DISABLE_HANDLER_TYPE_REQUIREMENTS,可以禁用显式类型检查,并允许编译器错误从实现中更深层的调用点出现(如果它们发生).在历史注意到此选项:
Asio 1.6.0/Boost 1.47
- ...
- 当完成处理程序不满足必要的类型要求时,添加了更友好的编译器错误.当C++ 0x可用时(当前支持
g++4.5或更高版本,以及MSVC 10),static_assert也用于生成信息性错误消息.可以通过定义来禁用该检查BOOST_ASIO_DISABLE_HANDLER_TYPE_REQUIREMENTS.
以下是演示此功能的完整示例.在其中,受管理的套接字的所有权通过以下unique_ptr方式传输到处理程序std::move():
#include <functional> // std::bind
#include <memory> // std::unique_ptr
#include <string> // std::string
#define BOOST_ASIO_DISABLE_HANDLER_TYPE_REQUIREMENTS
#include <boost/asio.hpp>
const auto noop = std::bind([]{});
int main()
{
using boost::asio::ip::tcp;
// Create all I/O objects.
boost::asio::io_service io_service;
tcp::acceptor acceptor(io_service, tcp::endpoint(tcp::v4(), 0));
auto socket1 = std::make_unique<tcp::socket>(std::ref(io_service));
tcp::socket socket2(io_service);
// Connect the sockets.
acceptor.async_accept(*socket1, noop);
socket2.async_connect(acceptor.local_endpoint(), noop);
io_service.run();
io_service.reset();
// Move ownership of socket1 to a handler that will write to the
// socket.
const std::string expected_message = "test message";
io_service.post([socket1{std::move(socket1)}, &expected_message] {
boost::asio::write(*socket1, boost::asio::buffer(expected_message));
});
io_service.run();
// Read from socket2.
std::vector<char> actual_message(socket2.available());
boost::asio::read(socket2, boost::asio::buffer(actual_message));
// Verify message.
assert(std::equal(
begin(expected_message), end(expected_message),
begin(actual_message), end(actual_message)));
}
Run Code Online (Sandbox Code Playgroud)