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

Что такое lambda-выражения в C++? Как захватывать переменные?

1.6 Junior🔥 181 комментариев
#STL контейнеры и алгоритмы#ООП и проектирование#Язык C++

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

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

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

Что такое lambda-выражения в C++? Как захватывать переменные?

Lambda-выражения — это анонимные функции, которые можно определить прямо в месте использования. Они появились в C++11 и существенно упростили код при работе с алгоритмами и колбэками.

Синтаксис lambda

[capture] (parameters) -> return_type { body }

Самый простой пример:

auto add = [](int a, int b) { return a + b; };
int result = add(3, 5);  // 8

// С явным типом возврата
auto mul = [](int a, int b) -> int { return a * b; };

// Без параметров
auto hello = []() { std::cout << "Hello\n"; };
hello();

Захват переменных (Capture Clause)

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

int x = 10;
auto func = [=]() { std::cout << x; };  // Копирует x
x = 20;
func();  // Выведет 10, а не 20!

Захват по значению создаёт копию переменной на момент создания lambda:

int multiplier = 5;
auto times = [multiplier](int x) { return x * multiplier; };
multiplier = 10;
std::cout << times(3);  // 15, а не 30

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

int count = 0;
auto increment = [&]() { count++; };
increment();
increment();
std::cout << count;  // 2

При захвате по ссылке lambda видит текущее значение переменной. Опасно! Если переменная уничтожится, ссылка будет висящей (dangling):

std::function<void()> createLambda() {
    int x = 10;
    return [&]() { std::cout << x; };  // ✗ ОПАСНО!
    // x уничтожится при выходе из функции, ссылка станет невалидной
}

Выборочный захват

Захватывай только нужные переменные:

int a = 1, b = 2, c = 3;

// Захвати a и b по значению, остальные по ссылке
auto func = [a, b, &c](int x) {
    return a + b + c + x;
};

// Захвати всё по значению, кроме c (по ссылке)
auto func2 = [=, &c]() {
    return a + b + c;
};

// Захвати всё по ссылке, кроме a (по значению)
auto func3 = [&, a]() {
    return a + c;
};

Модификация захватанных переменных

По умолчанию lambda не может изменять захватанные переменные:

int x = 5;
auto func = [x]() {
    x++;  // ✗ Ошибка! Нельзя изменять
};

Чтобы разрешить модификацию, добавь mutable:

int x = 5;
auto func = [x]() mutable {
    x++;  // ✓ Теперь можно
    return x;
};
func();  // 6
std::cout << x;  // 5 — исходная переменная не изменилась!

При захвате по ссылке, mutable не требуется:

int x = 5;
auto func = [&]() {
    x++;  // ✓ Работает без mutable
};
func();
std::cout << x;  // 6 — изменение видно снаружи

Практические примеры

Сортировка с компаратором

std::vector<int> nums = {3, 1, 4, 1, 5, 9};

// Lambda вместо функтора
std::sort(nums.begin(), nums.end(), 
    [](int a, int b) { return a > b; });  // По убыванию

Фильтрация в std::find_if

std::vector<int> nums = {1, 2, 3, 4, 5};
auto it = std::find_if(nums.begin(), nums.end(),
    [](int x) { return x % 2 == 0; });  // Найди первое чётное

Обработка с сохранением состояния

int sum = 0;
std::vector<int> nums = {1, 2, 3, 4};

std::for_each(nums.begin(), nums.end(),
    [&sum](int x) { sum += x; });  // Захвати sum по ссылке

std::cout << sum;  // 10

Возврат lambda из функции (C++14+)

auto makeAdder(int n) {
    return [n](int x) { return x + n; };  // Захвати n по значению
}

auto add5 = makeAdder(5);
std::cout << add5(10);  // 15

Правила для захвата

  • По значению ([=]) — когда переменная должна "заморозиться"
  • По ссылке ([&]) — когда нужно видеть изменения снаружи
  • Выборочно — когда нужна точность
  • Избегай [&] в возвращаемых lambdas — риск висящей ссылки

C++14 и далее: обобщённые lambda

// C++14 — параметры можно объявлять как auto
auto sum = [](auto a, auto b) { return a + b; };
std::cout << sum(1, 2);          // 3
std::cout << sum(1.5, 2.5);      // 4
std::cout << sum("Hello"s, " World"s);  // "Hello World"

Итого

Lambda — это мощный инструмент для:

  • Компактных функций в алгоритмах
  • Колбэков без создания отдельных классов-функторов
  • Замыканий с сохранением контекста

Главное правило: всегда чётко понимай, как и что ты захватываешь!