Зачем нужны поля в лямбда-функции?

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

Ответ

Поля (или захват переменных) позволяют лямбда-функции в C++ получать доступ к данным из окружающей области видимости. Это ключевой механизм для создания замыканий.

Основные способы захвата:

  • По значению [=] или [x]: Создаётся копия переменной на момент создания лямбды. Изменения внутри лямбды не затрагивают оригинал.
  • По ссылке [&] или [&x]: Лямбда работает непосредственно с исходной переменной. Изменения внутри лямбды видны снаружи.
  • Инициализирующий захват (C++14) [x = std::move(obj)]: Позволяет перемещать или инициализировать захватываемые объекты.

Пример:

int counter = 0;
std::string msg = "Hello";

// Захват counter по ссылке, msg по значению
auto lambda = [&counter, msg]() {
    ++counter; // Меняет исходный counter
    std::cout << msg << " called " << counter << " timesn"; // msg - копия
};

lambda(); // Вывод: Hello called 1 times
lambda(); // Вывод: Hello called 2 times
// Исходная msg осталась "Hello"

Критические нюансы:

  1. Время жизни: Захват по ссылке опасен, если лямбда (например, сохранённая в std::function) переживёт захваченную переменную, что приведёт к неопределённому поведению.
  2. По умолчанию const: Лямбда, захватившая переменные по значению, по умолчанию является const. Для модификации таких копий требуется спецификатор mutable.
  3. this: Для захвата членов класса внутри метода используется [this] или [*this] (C++17, захват копии объекта).