Binary size when using std::function with lambda expression


When using std::function instead of function pointer (see the sample of code) on Mac, we get a huge difference between size of generated binary (80ko when using function pointer and 157ko whit std::function).

I use Xcode to build debug with -O0 -std=gnu++14 and libc++.

It doesn’t seem to have the same result on windows or linux.

Is it something normal ?

Here’s the code sample :



int main(int argc, const char * argv) {

std::function<void()> f = {std::cout << “LOG2\n”;};

// void (*f)() = {std::cout << “LOG3\n”;};


return 0;




Cyril Makloufi

Email :
Web :

66 route de Sartrouville
Parc Les Erables - Batiment 4
78230 Le Pecq - France

Standard : +33 1 30 53 92 00

Hi Cyril, generated 467 lines of assembler with clang trunk and -O0 (on Linux, I suppose), versus 58 lines for the function pointer.

With -O2 it was 76 lines vs 20 lines.
(Nine lines are always used to initialize iostream and set up its destruction)

There may be extra code linked in from libc++ for std::function.


image0b65ab.JPG might be a good place to send this as well, since it’s possible it’s a libc++ thing.


This is expected. std::function<void()> is a library type. It does “type erasure,” a C++ technique which you can learn about here: (“Back to Basics: Type Erasure”, CppCon 2019)

Contrast with core-language lambda expressions: (“Back to Basics: Lambdas from Scratch”, CppCon 2019)

You can do a lot of things with std::function<void()> f that you can’t do with void (*f)(); for example, std::function<void()> f can hold a copy of a lambda which itself has captures.

int i = 42;
std::function<void()> f = & { std::cout << i; }; // OK
void (*g)() = & { std::cout << i; }; // Ill-formed

You pay for this flexibility in code size (and speed) (and, in many cases, heap-allocations).

Additionally, std::function is notoriously inefficient even as type-erased types go. This is partly because the paper standard requires it to do so much (e.g. the .target_type() method); and partly because its implementation was done ~15 years ago and maybe we’d like to apply some lessons learned since then, but that would break ABI.