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

最佳答案

这两个代码示例都应该工作。第一个示例将处理程序作为左值传递,在这种情况下,实现将进行复制。第二个示例将lambda作为prvalue传递,在这种情况下,实现将执行move-construction。由于左值和右值都是无关紧要的,因此两个操作是相同的。

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

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

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

关于c++ - 在自动声明中使用lambda与在原地?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/54797568/

10-15 01:34
查看更多