← Назад к вопросам

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

1.8 Middle🔥 121 комментариев
#Язык C++

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI28 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Понимание Capture в лямбда-функциях C++

"Поля" в лямбда-функции — это механизм захвата (capture) переменных из окружающей области видимости. Лямбда-функция может использовать переменные, определённые за её пределами, только если явно их захватить.

Что такое capture list []

Фигурные скобки [] в начале лямбды определяют, какие переменные из внешней области видимости будут доступны внутри лямбды:

int x = 5;
int y = 10;

// [x, y] — захватываем обе переменные
auto lambda = [x, y]() {
    std::cout << x << " " << y << std::endl;  // Ошибка! x и y не определены
    return x + y;
};

auto lambda2 = [x, y]() {
    return x + y;  // OK! x и y захвачены
};

Типы захвата

[=] — захват по значению (copy)

int x = 5;
auto lambda = [=]() {
    std::cout << x << std::endl;  // x = 5, копия
};
x = 20;  // Меняем оригинальный x
lambda();  // Выведет 5, не 20! (была копия)

Преимущества:

  • Лямбда независима от изменений в оригинальных переменных
  • Потокобезопасна
  • Предсказуемо

Недостатки:

  • Затраты памяти на копирование
  • Если переменная большой объект (vector), копируется целая копия

[&] — захват по ссылке (reference)

int x = 5;
auto lambda = [&]() {
    std::cout << x << std::endl;
};
x = 20;
lambda();  // Выведет 20! (ссылка на оригинал)

Преимущества:

  • Никакого копирования, экономия памяти
  • Видим актуальные изменения переменной

Недостатки:

  • ОПАСНО! Если переменная выходит из области видимости, ссылка становится невалидной
  • Race conditions при многопоточности

[x] — захват конкретной переменной по значению

int x = 5, y = 10;
auto lambda = [x]() {
    return x * 2;  // x захвачена
    // return y * 2;  // Ошибка! y не захвачена
};

[&x] — захват конкретной переменной по ссылке

int x = 5, y = 10;
auto lambda = [&x]() {
    return x * 2;  // x захвачена по ссылке
    // return y * 2;  // Ошибка! y не захвачена
};

[=, &x] — смешанный захват (большинство по значению, x по ссылке)

int x = 5, y = 10;
auto lambda = [=, &x]() {
    x = 100;       // OK! x по ссылке, можем менять
    // y = 100;     // Ошибка! y по значению, readonly
};

[&, x] — смешанный (большинство по ссылке, x по значению)

int x = 5, y = 10;
auto lambda = [&, x]() {
    y = 100;       // OK! y по ссылке
    // x = 100;     // Ошибка! x по значению, readonly
};

Практический пример: обработка данных

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> data = {1, 2, 3, 4, 5};
    int multiplier = 2;
    int sum = 0;
    
    // Захватываем multiplier по значению, sum по ссылке
    std::for_each(data.begin(), data.end(), 
        [multiplier, &sum](int value) {
            int result = value * multiplier;
            sum += result;  // Можем менять sum (по ссылке)
            std::cout << result << " ";
        }
    );
    
    std::cout << "\nSum: " << sum << std::endl;  // sum = 2+4+6+8+10 = 30
    return 0;
}

Mutable лямбды

По умолчанию переменные, захваченные по значению, readonly:

int x = 5;
auto lambda = [x]() {
    // x = 10;  // Ошибка! x const
    std::cout << x << std::endl;
};

// Решение: mutable
auto lambda_mutable = [x]() mutable {
    x = 10;  // OK! Меняем копию, не оригинал
    std::cout << x << std::endl;
};

Когда и что захватывать

Захватывайте по значению [=], если:

  • Лямбда будет вызвана позже (callback, async задачи)
  • Нужна потокобезопасность
  • Переменная может выйти из области видимости

Захватывайте по ссылке [&], если:

  • Лямбда вызывается сразу в одной области видимости
  • Переменная гарантированно жива во время вызова
  • Нужно сэкономить память (большие объекты)

Опасность: Dangling references

std::function<void()> create_lambda() {
    int x = 5;
    return [&x]() {  // ОПАСНО! &x выходит из области видимости
        std::cout << x << std::endl;
    };
}

int main() {
    auto lambda = create_lambda();
    lambda();  // Undefined behavior! x уже не существует
}

Итог

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