C ++ лямбда-выражения: перехватывается ссылками - PullRequest
1 голос
/ 03 октября 2019

Я заметил, что в проекте я работал во многих местах, где лямбда-выражения захватывают указатель на это, но не используют его. Приводит ли это к каким-то накладным расходам, таким как копирование указателя, или оптимизируется компилятором?

void MyClass::SomeFunction()
{
    ...
    grid->ForEachItem([this](const Item& item)
    {
        // Some code doesn't use this
    }
}

И тот же вопрос, предназначенный для захвата всего по ссылке [&]

Ответы [ 2 ]

5 голосов
/ 03 октября 2019

Я лично рекомендую не захватывать this, если он не используется, но, скорее всего, не из-за соображений производительности.

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

В случае лямбда-захвата, компилятору разрешено фактически не захватывать объекты, которые не используются, дажеесли они захвачены копией [=]. И вдобавок ко всему, тот факт, что лямбда-тело полностью видимо для компилятора в сочетании с правилом , как будто , в основном гарантирует, что на современном компиляторе с включенными оптимизациями вам не нужно беспокоиться о производительностио том, что вы захватываете.

Однако причина, по которой я рекомендую снимать то, что вы не используете, заключается в удобочитаемости и выразительности выражения. Если лямбда использует this или любую другую переменную, которая является ссылкой или указателем, вам нужно убедиться, что лямбда не переживает то, что захватывает. Например, если я вижу лямбду, которая захватывает this и возвращается за пределы метода, я очень нервничаю и делаю все возможное, чтобы убедиться, что захваченный объект не истекает до того, как лямбда может быть вызвана. И даже если это не проблема (например, лямбда не выходит за пределы метода), простая путаница читателя («эта лямбда не должна использовать состояние объекта, почему тогда она захватывает this?»). ") достаточно убедительного аргумента, чтобы его избежать.

Просматривая список захвата лямбды, вы должны сказать, когда безопасно вызывать его. Лямбда лежит , если она захватывает ссылку или указатель на то, что она не использует. Не пишите ложные лямбды.


TLDR без накладных расходов, но не делайте это из соображений читабельности и выразительности.

1 голос
/ 03 октября 2019

Приводит ли это к каким-то накладным расходам, таким как копирование указателя

Что касается абстрактной машины: Да. Будет копия указателя, и захваченный указатель увеличит размер лямбда-объекта.

Но если компилятор развернет вызов функции в строке, то все это можно будет оптимизировать до нуля.

И тот же вопрос, предназначенный для захвата всех по ссылке [&]

Функция захвата по умолчанию не будет захватывать ничего, что не используется лямбда-выражением, независимо от того, используете ли вы значение илизахват ссылки.

...