What kind of magic does the std::function<void(int&)>
from C++11 that its sizeof = 32
? If I'd store the function reference as a pointer, it'd cost only 8 bytes
(on a 64 bit machine).

- 23,584
- 43
- 124
- 195
-
2Probably small-functor optimization. – ildjarn Nov 21 '12 at 23:07
-
2Consider the size of member function pointers, first of all. – GManNickG Nov 21 '12 at 23:12
-
1@GManNickG Yes, that's what I'm asking for, i.e. the internals. These STL files are quite unreadable so I wonder if somebody knows it precisely. – Cartesius00 Nov 21 '12 at 23:15
-
2I don't think it can be reasonably claimed that `std::function` is or ever was part of the STL. – Lightness Races in Orbit Nov 21 '12 at 23:17
-
2@LightnessRacesinOrbit O wow. You're getting mild these days :) – sehe Nov 21 '12 at 23:49
2 Answers
For std::function<Signature>
it is a trade-off between object size and allocation which is interesting: For small function objects it is desirable to avoid an allocation. On the other hand, doing so increases the object size. For the small function optimization to be useful and not introduce overheads when actually calling the object, the object size needs to be at least two pointers plus some memory to store simple function objects. It seems that a size of 32 bytes is exactly this (on a system where sizeof(T*)
is 8).
That is, internally a std::function<Signature>
object stores an inheritance hierarchy: The base class provides the interface to be called, delegating to a templatized derived which implements the call interface (plus, probably, some clone()
functionality). In an implementation optimized for size the function object would just keep a pointer to the base, but to avoid allocation it would set aside some internal storage to allocate the entire object in and point to this object (the internal pointer avoids a condition when actually calling the function object). The memory needed for the object is a virtual function pointer plus any data for the actual function object the std::function<Signature>
object is initialized with. To accommodate member functions with their object it seems that two more words is reasonably small.

- 378,754
- 76
- 643
- 1,055

- 150,225
- 13
- 225
- 380
-
1@LightnessRacesinOrbit: One pointer to point to the base and a virtual function pointer. Plus, the data for the actual function object. – Dietmar Kühl Nov 21 '12 at 23:22
-
I don't understand where the virtual function pointer comes from, but I'll leave it. – Lightness Races in Orbit Nov 21 '12 at 23:27
-
Internally, the `std::function
` uses a base class with a virtual function, e.g., `struct FB { virtual R call(A...) = 0; virtual ~FB() {} };` and when assigning a function object to the object it creates a corresponding derived class. – Dietmar Kühl Nov 21 '12 at 23:32 -
Looking at the actual implementation, it seems libstdc++ trades a run-time dispatch for storing a pointer in case the object is embedded into the actual function. libcxx uses a more vanilla implementation described above. – Dietmar Kühl Nov 21 '12 at 23:35
std::function
is indeed magic, as it can be constructed from any callable object! It will happily store any amount of state for you, even if on the surface you retain a measly void(int&)
signature.
There's certainly a price attached to this magic, which typically uses some sort of type erasure (i.e. a dynamic allocation and virtual dispatch) internally. The details vary, but the resulting objects are certainly "heavy" — which is why they should be avoided in favour of auto
and templates whenever feasible!

- 464,522
- 92
- 875
- 1,084
-
How can one store a state in the `std::function` object? I thought that this `std::function` was only a kind of a "safe C++ function pointer", but it is more, right? – Cartesius00 Nov 21 '12 at 23:27
-
1@Martin: It's a lot more -- for starters, `std::function` is a *template*, not a class. And it is indeed full of magic. Lots of templated constructors and SFINAE etc. Look at the source if you want to get an idea. – Kerrek SB Nov 21 '12 at 23:29
-
5@Martin If I have `struct big { void operator()() {}; char dummy[N]; };` then I can store an arbitrary amount of bytes in an `std::function
f = big {};`. – Luc Danton Nov 22 '12 at 06:02 -