我正在尝试学习现代C ++,并且正在使用Boost.Asio进行网络连接。我编写了一个TCP连接类,该类使用Asio的异步操作。当前,这是我从套接字读取数据的方法:
template<class T>
inline auto connection<T>::read(size_t length) -> void
{
auto handler = [&](const boost::system::error_code& error, size_t bytes_transferred) {
if (error == boost::asio::error::eof or error == boost::asio::error::connection_reset) {
close();
} else {
on_read(bytes_transferred);
}
};
socket.async_read_some(boost::asio::buffer(read_buffer, length), handler);
}
在这里,我用auto分别声明了读取处理程序,因为我认为它比就地lambda(即,
)更具可读性。template<class T>
inline auto connection<T>::read(size_t length) -> void
{
socket.async_read_some(boost::asio::buffer(read_buffer, length), [&](const boost::system::error_code& error, size_t bytes_transferred) {
if (error == boost::asio::error::eof or error == boost::asio::error::connection_reset) {
close();
} else {
on_read(bytes_transferred);
}
});
}
但是我在第一个版本中遇到了分段错误,我相信这是因为当方法超出范围时,处理程序lambda丢失了。然后我尝试使用std :: move
移动处理程序socket.async_read_some(boost::asio::buffer(read_buffer, length), std::move(handler));
这似乎可以修复段错误。
现在我的问题是:使用第一个版本(带有std :: move)与就地版本是否存在任何性能或其他问题?您认为哪种方法更好?
答案 0 :(得分:1)
这两个代码示例都应该起作用。第一个示例将处理程序作为左值传递,在这种情况下,实现将进行复制。第二个示例将lambda作为prvalue传递,在这种情况下,实现将执行move-construction。因为左值和右值都是微不足道的,所以两个操作是相同的。
Networking TS中的异步启动功能(扩展名为Asio和Boost.Asio)通过执行“衰变副本”获得处理程序的所有权。这意味着将根据参数是否为左值来复制或移出处理程序。
我不确定您的第一个示例为何会崩溃,但是与lambda的寿命无关。出于明显的原因,异步启动函数从不通过引用接收句柄,而始终通过衰落副本获得所有权。
您的代码中肯定还有其他问题,您尚未粘贴的部分。例如,在函数返回后如何使连接对象保持活动状态?