Использование лямбды с автоматическим объявлением против на месте? - PullRequest
0 голосов
/ 21 февраля 2019

Я пытаюсь выучить современный 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, потому что я думаю, что он выглядит более читабельным, чем лямбда на месте, т.е.

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);
        }
    });
}

Однако я столкнулся с ошибкой сегментации с первой версией, и я считаю, что это потому, что лямбда-обработчик теряется, когда метод выходит из области видимости.Затем я попытался переместить обработчик с помощью команды std :: move

socket.async_read_some(boost::asio::buffer(read_buffer, length), std::move(handler));

, которая, кажется, исправляет ошибку сегмента.

Теперь мой вопрос: есть ли какие-либо проблемы с производительностью или другие проблемы с использованием первой версии (с std :: move) и на месте?Какой из них вы считаете лучшей практикой?

1 Ответ

0 голосов
/ 21 февраля 2019

Оба эти примера кода должны работать.Первый пример передает обработчик как lvalue, и в этом случае реализация создаст копию.Во втором примере лямбда-выражение передается в качестве prvalue, и в этом случае реализация будет выполнять move-construction.Поскольку и lvalue, и prvalue тривиальны, эти две операции одинаковы.

Асинхронные инициирующие функции в TS сети (и, соответственно, Asio и Boost.Asio) становятся владельцами обработчиков, выполняя "decay-copy"«.Это означает, что обработчик либо копируется, либо перемещается из зависимости от того, является ли аргумент lvalue или нет.

Я не уверен, почему ваш первый пример дает сбой, но он не имеет никакого отношения к времени жизни лямбды.По очевидным причинам асинхронные инициирующие функции никогда не получают дескриптор по ссылке и всегда получают право собственности с помощью decay-copy.

Должна быть другая проблема с вашим кодом, в той части, которую вы не вставили.Например, что поддерживает объект подключения после возврата из функции?

...