2026-06-29
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:
double to be 8-byte aligned even on a 32-bit core, so this isn't a bug — it's the platform meeting STL implementation choices.operator new returning nullptr, combined with exceptions disabled (typical in Zephyr builds), gives undefined behavior that looks like "the lambda forgot its captures."Direction toward a solution:
-fno-exceptions visibility into __throw_bad_function_call and inspect std::__function::_Function_handler in your libstdc++. If the closure goes to the heap, ensure operator new is actually wired up in Zephyr (CONFIG_CPLUSPLUS + CONFIG_GLIBCXX_LIBCPP, plus a working allocator).float if precision allows. The nRF9151 has no double-precision FPU anyway — every double op is softfloat.std::function entirely. On embedded, prefer etl::delegate, tl::function_ref, or a hand-rolled type-erased callable with a statically-sized aligned buffer you control (alignas(8) std::byte storage[N]).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.
