std::function discards lambda closure silently

2026-06-29

Stack Overflow: View Question

Tags: c++, lambda, stl, embedded, zephyr-rtos

Score: 2 | Views: 226

The asker is building a value-conversion class on an nRF9151 (Cortex-M33, 32-bit) under Zephyr. They wrap a lambda in std::function. When the lambda captures a double, the closure data is silently lost — the function object appears to "discard" the capture rather than throwing or producing a compile error.

The diagnosis is on the right track: std::function implementations have a fixed-size Small Buffer Optimization (SBO) region embedded in the object so that small callables avoid a heap allocation. The SBO storage has a declared alignment. On a 32-bit ARM target, libstdc++/libc++ typically aligns the SBO to alignof(void*) = 4 bytes. A lambda capturing a double needs 8-byte alignment. When the closure's required alignment exceeds the SBO's alignment, the implementation falls back to heap allocation — but on a freestanding/embedded toolchain with no operator new, or with exceptions disabled, that fallback can silently misbehave.

Why it's interesting:

Direction toward a solution:

Gotchas: Don't trust that "small lambda" means "fits in SBO" — alignment, not just size, can push you to heap. And in Zephyr, the C++ runtime is often only partially initialized, so heap-allocating function objects can fail at link or load time without a clear error.

The challenge: When STL implementation defaults (SBO alignment) meet ARM ABI rules (8-byte doubles on a 32-bit core) in a freestanding environment, the result is silent data loss that no compiler warning will catch.

All newsletters