Открытый канал ID 76989124909096

C++ geek

Учим C/C++ на примерах

Публикации за период

По реакциям

Поиск и вся лента — после бесплатной регистрации. Свои даты — по подписке; владелец канала видит их бесплатно. Сортировка по реакциям — по подписке. Зарегистрироваться

Загрузка…

🕵️‍♂️ Анатомия лямбд: Что скрывает компилятор и где прячутся тормоза?

Мы привыкли писать auto func = [x](int y) { return x + y; }; и думать о лямбдах как о «магических» встроенных функциях. Но в C++ нет никакой магии. На уровне компилятора лямбд не существует.

Лямбда-выражение - это просто синтаксический сахар для создания анонимного класса (функтора).

⚙️ Что происходит под капотом?

Когда вы пишете такой код:

int multiplier = 10;
auto doMath = [multiplier](int val) {
return val * multiplier;
};

Компилятор молча генерирует для вас класс с уникальным непроизносимым именем и перегруженным оператором ():

// Примерно это генерирует компилятор:
class __Lambda_Uniq_42 {
int multiplier; // Захваченная переменная стала полем класса
public:
__Lambda_Uniq_42(int m) : multiplier(m) {}

// Сам код лямбды:
auto operator()(int val) const {
return val * multiplier;
}
};

// А ваше создание лямбды превращается в:
auto doMath = __Lambda_Uniq_42(multiplier);


Вывод №1: Блок захвата [...] - это просто конструктор класса и его поля. Если вы захватываете по ссылке [&x], полем класса станет ссылка.

🚨 Где прячутся скрытые аллокации?

Сама по себе лямбда создается на стеке. Никаких new или malloc не происходит. Это работает мгновенно.

Тормоза начинаются, когда мы решаем сохранить лямбду с помощью std::function.

// 🚀 БЫСТРО (Zero-cost)
auto fast_lambda = [a, b, c]() { ... };

// 🐢 МОЖЕТ БЫТЬ МЕДЛЕННО (Heap allocation)
std::function<void()> slow_lambda = [a, b, c, d, e]() { ... };

std::function - это тяжелая обертка (Type Erasure). Она должна уметь хранить любой вызываемый объект с нужной сигнатурой.
Чтобы избежать выделения памяти в куче, в std::function встроена оптимизация для маленьких объектов (SBO - Small Buffer Optimization). Размер этого буфера обычно равен размеру нескольких указателей (например, 16-32 байта).

* Если ваша лямбда захватывает мало данных (или ничего) - она поместится во внутренний буфер std::function. Аллокаций нет.
* Если вы написали [=] и захватили кучу тяжелых переменных (или несколько толстых строк/векторов по значению) - размер сгенерированного класса превысит буфер. std::function будет вынужден вызвать new и выделить память в куче.

💡 Правила чистого кода с лямбдами:

1. Храните через auto: Всегда используйте auto для локальных лямбд. Это бесплатно.
2. Передавайте через шаблоны: Если функция принимает лямбду, лучше сделать её шаблоном template <typename Func> void DoWork(Func f), чем принимать std::function. Шаблон сохранит тип лямбды и позволит компилятору заинлайнить код.
3. Используйте std::function только на границах API: Когда вам действительно нужно хранить функции разного типа в одном контейнере (например, вектор коллбеков) или передать их через границу динамической библиотеки.
4. Не пишите [=] вслепую: Захватывайте только то, что реально нужно. Это спасет и от лишних аллокаций, и от случайного копирования тяжелых объектов.

#cpp #lambdas #optimization #memory #under_the_hood #coding #tips

➡️ @channel_cpp_geek
Просмотры: 62
Перейти в пост Открыть в MAX Сообщить о неточности
ВКонтакте Телеграм Одноклассники
Избранное в datool.ru

Следите за каналом в личном кабинете

Зарегистрируйтесь в datool.ru, чтобы добавить канал «C++ geek» в избранное и отслеживать его показатели.

Зарегистрироваться
Для владельцев каналов

Подтвердите свой канал

Войдите или зарегистрируйтесь в datool.ru, затем добавьте нашего бота в канал по инструкции в личном кабинете. После проверки владения замок исчезнет и вам станет доступно управление каналом.

Войти или зарегистрироваться

Сообщить о неточности

Опишите, что нужно исправить. Если есть источник, добавьте ссылку.

Вы покидаете datool.ru

Ссылка ведёт на внешний сайт. datool.ru не отвечает за его содержимое — проверьте адрес, прежде чем вводить пароли или платёжные данные.

Переход через 10 с

Перейти