Неужели плохая практика всегда захватывать все в выражении лямбды?

std::function<int()> void f1()
{
    int a, b, c, d, ..., x, y, z;

    return [=] { return a + b + c; };
}

против.

std::function<int()> void f2()
{
    int a, b, c, d, ..., x, y, z;

    return [a, b, c] { return a + b + c; };
}

Излишне говорить, что первая короче, удобнее и элегантнее, чем последняя.

Однако я все еще беспокоюсь:

С точки зрения производительности последний всегда лучше первого?

Является ли стандарт гарантией, что лямбда-выражение захватывает только необходимые переменные? т.е. в первом примере захватываются только a, b, c, неиспользуемые переменные d,..., x, y, z не являются.

Ответы

Ответ 1

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

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

Для любого, кто волнует, точная формулировка стандарта (§5.1.2/11, 12):

11 Если лямбда-выражение имеет связанный с захватом-умолчанию и его составной оператор odr-uses (3.2) this или переменную с автоматической продолжительностью хранения, а объект, использующий odr, явно не захвачен, тогда odr -используемая сущность считается неявно зафиксированной; такие субъекты должны быть объявлены в пределах охвата лямбда-выражения. [Заметка завершена]

12 Объект захватывается, если он зафиксирован явно или неявно. [...]

Резюме: неявная спецификация захвата ([=] или [&]) будет захватывать только переменные, которые используются в лямбда.

Ответ 2

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

Пусть компилятор делает вывод, что необходимо, когда это возможно.
Это не сделает ошибку, и она не "случайно" захватит что-то неиспользованное внутри лямбды.
Если вы хотите быть явным (иногда это имеет смысл), то, что традиционные функторы идеально подходят.

Ответ 3

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