🍬 Closure size и SBO: когда лямбда уходит в куч
Размер объекта-замыкания напрямую влияет на то, выделяется ли память в куче при хранении в std::function. Понимание Small Buffer Optimization критично для low-latency кода.
⚡️ std::function содержит внутренний буфер (обычно 16–32 байта в зависимости от реализации). Если closure влезает — heap allocation не происходит:
// sizeof closure = sizeof(int) = 4 байта → SBO
auto f1 = [x = 42]() { return x; };
std::function<int()> sf1 = f1; // нет heap allocation
// sizeof closure = 3 * sizeof(string) → возможно > SBO
std::string s1, s2, s3;
auto f2 = [s1, s2, s3]() { return s1 + s2 + s3; };
std::function<int()> sf2 = f2; // возможно heap allocation
🔍 Практическое правило: захватываешь больше 3-х примитивных значений — жди heap allocation. std::string, вектор, любой объект с указателем внутри — почти гарантия.
⚠️ Решения для latency-sensitive кода:
• std::move_only_function (C++23) — меньше overhead, нет копирования
• Ручной std::aligned_storage + placement new
❗️ SBO — деталь реализации стандартной библиотеки, не гарантированная стандартом. Для критичного кода измеряй, не предполагай. Конкретный порог зависит от libstdc++/libc++/MSVC STL.