Ответ
В C++ лямбда-выражения могут захватывать переменные из окружающего контекста несколькими способами, что определяет время жизни и доступ к этим переменным.
Основные способы захвата:
-
Захват по значению
[=]Создается копия переменной на момент создания лямбды. Изменения внутри лямбды не затрагивают оригинал.int x = 42; auto lambda = [=]() { // x - локальная копия со значением 42 return x + 1; // Возвращает 43, но x остаётся 42 }; -
Захват по ссылке
[&]Лямбда работает с оригинальной переменной. Опасно, если лямбда переживёт захваченную переменную.int y = 10; auto lambda = [&]() { y++; // Модифицирует оригинальную переменную y }; lambda(); // Теперь y = 11 -
Явный (смешанный) захват
[var1, &var2]Позволяет точно контролировать способ захвата для каждой переменной.int a = 1, b = 2; auto lambda = [a, &b]() { return a + b; // a - по значению, b - по ссылке }; -
Инициализирующий захват
[name = expr](C++14) Позволяет создавать новые члены лямбды, инициализируемые произвольным выражением. Особенно полезен для перемещения (std::move) или захвата unique_ptr.std::unique_ptr<Resource> resource = std::make_unique<Resource>(); auto lambda = [capturedResource = std::move(resource)]() { capturedResource->use(); // Захвачен по перемещению }; // resource теперь nullptr -
*Захват указателя
thisи `this(C++17)**[this]захватывает указатель на текущий объект по ссылке.[*this]` захватывает копию текущего объекта по значению, что безопаснее при асинхронных операциях.class Processor { int m_data; public: auto getLambda() { // Захват копии объекта, а не указателя return [*this]() { return m_data; }; } };
Практическое правило: По умолчанию предпочитайте явный захват по значению для примитивов и маленьких объектов, используйте инициализирующий захват для управления владением (особенно с move-only типами), а захват по ссылке — только когда уверены в времени жизни объекта.