Какие риски есть при использовании лямбда-выражений в C++?

«Какие риски есть при использовании лямбда-выражений в C++?» — вопрос из категории C++ Core, который задают на 25% собеседований C/C++ Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Основные риски связаны с управлением временем жизни объектов и семантикой захвата.

1. Висячие ссылки при захвате по ссылке ([&]):

auto make_dangerous_lambda() {
    int local_var = 42;
    // Захват по ссылке. Лямбда переживет 'local_var' -> неопределенное поведение.
    return [&]() { std::cout << local_var; };
}
// Вызов возвращенной лямбды приведет к чтению мусора.

2. Неявный захват нежелательных переменных:

int global_counter = 0;
int value = 10;

// [=] захватывает ВСЕ нестатические локальные переменные по значению,
// но также неявно захватывает `global_counter` по ссылке!
auto lambda = [=]() { return value + global_counter; };
// Изменение global_counter извне влияет на результат лямбды.

3. Проблемы с производительностью и размером:

  • Захват больших объектов по значению ([=]) ведет к копированию.
  • Захват по ссылке ([&]) может помешать оптимизациям компилятора.
  • Каждая лямбда имеет уникальный анонимный тип, что может увеличить размер шаблонного кода.

4. Сложности с рекурсией и явным указанием типа:

// Для рекурсии нужно использовать std::function или фиксировать тип через auto в аргументе.
std::function<int(int)> factorial = [&factorial](int n) -> int {
    return n <= 1 ? 1 : n * factorial(n - 1);
};
// Или с использованием Y-комбинатора (более эффективно, но сложнее).

Лучшие практики:

  • Явный захват: Используйте [var1, &var2] вместо [=] или [&].
  • Захват this: В методах класса предпочитайте [this] или [=, this] (C++20) вместо [&], чтобы избежать случайного захвата членов класса по ссылке.
  • Универсальные ссылки в шаблонах: Для generic-лямбд используйте auto&& параметры.
  • Для асинхронных задач: Если лямбда выполняется позже, всегда захватывайте по значению ([=]) или используйте std::shared_ptr для разделяемых данных.