在自动声明中使用lambda与在原地?

时间:2019-02-21 00:51:44

标签: c++ segmentation-fault boost-asio c++17

我正在尝试学习现代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)与就地版本是否存在任何性能或其他问题?您认为哪种方法更好?

1 个答案:

答案 0 :(得分:1)

这两个代码示例都应该起作用。第一个示例将处理程序作为左值传递,在这种情况下,实现将进行复制。第二个示例将lambda作为prvalue传递,在这种情况下,实现将执行move-construction。因为左值和右值都是微不足道的,所以两个操作是相同的。

Networking TS中的异步启动功能(扩展名为Asio和Boost.Asio)通过执行“衰变副本”获得处理程序的所有权。这意味着将根据参数是否为左值来复制或移出处理程序。

我不确定您的第一个示例为何会崩溃,但是与lambda的寿命无关。出于明显的原因,异步启动函数从不通过引用接收句柄,而始终通过衰落副本获得所有权。

您的代码中肯定还有其他问题,您尚未粘贴的部分。例如,在函数返回后如何使连接对象保持活动状态?