Захват в лямбда-выражениях: по значению, по ссылке, mutable
Продуманно выбирайте предложения захвата и разбирайтесь в состоянии лямбда-выражений.
«Захват в лямбда-выражениях: по значению, по ссылке, mutable» — бесплатный урок C++ Academy на CoddyKit. Это урок 2 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения C++ Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс C++ Academy содержит 4 уроков всего.
Итоги по захватам
Предложение захвата лямбда-выражения перечисляет переменные из окружающей области видимости, которые оно может использовать. Режим захвата определяет способ доступа к каждой переменной.
Захват по значению
Имена, перечисленные без &, копируются при создании лямбда-выражения. Лямбда-выражение владеет своей копией.
int n = 5;
auto f = [n]() { return n * 2; };
n = 10;
std::cout << f(); // 10 (captured n was 5)Захват по ссылке
Имена с & сохраняются как ссылки на внешнюю переменную. Изменения распространяются в обоих направлениях.
int counter = 0;
auto inc = [&counter]() { ++counter; };
inc(); inc();
std::cout << counter; // 2Захват по умолчанию: =
[=] захватывает по значению всё используемое в теле лямбда-выражения. Это удобно, но может привести к неожиданностям: захватываются только переменные, на которые есть ссылки.
int a = 1, b = 2, c = 3;
auto f = [=]() { return a + c; }; // captures a and c (not b)Захват по умолчанию: &
[&] захватывает по ссылке всё используемое. Будьте осторожны: ссылки на локальные переменные становятся недействительными, если время жизни лямбда-выражения превышает область видимости.
int n = 0;
auto bad = [&]() { return n; };
return bad; // n dies, lambda danglesСмешивание режимов
Объединяйте захват по умолчанию с конкретными захватами. Перечисляйте отдельные переменные, чтобы переопределить режим по умолчанию.
int a = 1, b = 2;
auto f = [=, &b]() { // a by value, b by reference
return a + b;
};Изменяемые лямбда-выражения
Переменные, захваченные по значению, внутри лямбда-выражения являются const. Добавьте mutable, чтобы лямбда-выражение могло изменять свою захваченную копию.
int n = 5;
auto inc = [n]() mutable {
++n;
return n;
};
inc(); inc();
std::cout << n; // 5 (outer unchanged)Инициализирующие захваты (C++14)
Захватывайте результат выражения под новым именем. Это позволяет выполнять захват перемещением и задавать вычисляемые начальные значения.
auto ptr = std::make_unique<int>(42);
auto f = [p = std::move(ptr)]() {
return *p;
};
// ptr is now empty; p owns the int inside the lambdaЗахват this
Внутри функции-члена [this] захватывает указатель this — все члены доступны внутри лямбда-выражения.
Захват *this (C++17)
[*this] копирует весь объект в лямбда-выражение. Это полезно, когда лямбда-выражение живёт дольше исходного объекта.
Проблема: захват по ссылке и асинхронное выполнение
Никогда не захватывайте локальные переменные по ссылке в лямбда-выражение, выполняемое асинхронно: локальные переменные, скорее всего, будут уничтожены до вызова лямбда-выражения.
// BUG
int local = 42;
std::async([&local]() { use(local); }); // local dies, lambda danglesБыстрая проверка
Какой режим захвата подходит, чтобы лямбда-выражение владело объектом std::unique_ptr из внешней области видимости?
Итоги
Захват по значению создаёт копию, а захват по ссылке — псевдоним. Осторожно используйте захваты по умолчанию [=] и [&]. Ключевое слово mutable разрешает изменять копии, захваченные по значению. Инициализирующие захваты (C++14) позволяют выполнять захват перемещением.
Изучай C++ с ИИ-репетитором — бесплатно
Пиши и запускай код прямо в браузере, получай мгновенную помощь от ИИ-репетитора 24/7 и продолжи учиться на сайте или в приложении.
- Курсы
- 51
- Уроки
- 203
Часто задаваемые вопросы
Урок «Захват в лямбда-выражениях: по значению, по ссылке, mutable» бесплатный?
Да — полный текст урока «Захват в лямбда-выражениях: по значению, по ссылке, mutable» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс C++ Academy, подпишись на CoddyKit PRO. Курс C++ Academy содержит 4 уроков всего.
Чему я научусь в уроке «Захват в лямбда-выражениях: по значению, по ссылке, mutable»?
Продуманно выбирайте предложения захвата и разбирайтесь в состоянии лямбда-выражений. Ты практикуешь C++ Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать C++ Academy?
Предыдущий опыт не требуется. C++ Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 2 из 4.
Сколько времени занимает урок «Захват в лямбда-выражениях: по значению, по ссылке, mutable»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке C++ Academy?
Да. Каждый урок C++ Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Функциональные объекты и функторы
- Захват в лямбда-выражениях: по значению, по ссылке, mutable
- Обобщённые лямбда-выражения и замыкания в C++14
- std::function: вызываемые объекты со стиранием типа