使用自动声明的lambdas与就地?

问题描述 投票:2回答:1

我正在尝试学习现代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分别声明了read处理程序,因为我认为它看起来比就地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)和就地存在任何性能或其他问题吗?您认为哪一种更好的做法?

c++ segmentation-fault boost-asio c++17
1个回答
1
投票

这两个代码示例都应该有效。第一个示例将处理程序作为左值传递,在这种情况下,实现将进行复制。第二个示例将lambda作为prvalue传递,在这种情况下,实现将执行移动构造。由于左值和左值都是微不足道的,因此两个操作是相同的。

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

我不确定为什么你的第一个例子崩溃,但它与lambda的生命周期无关。出于显而易见的原因,异步启动函数永远不会通过引用接收句柄,并始终通过decay-copy获取所有权。

在您未粘贴的部分中,您的代码必定存在其他问题。例如,在函数返回后保持连接对象的活动是什么?

© www.soinside.com 2019 - 2024. All rights reserved.