How std::function is Implemented: Type-Erasure and Heap Allocation
A key implementation detail of std::function is its ability to wrap any callable, including lambda expressions. While lambdas vary in size, std::function maintains a fixed size. This is achieved through a technique called type-erasure.
Take a simplified example of std::function
struct callable_base { virtual int operator()(double d) = 0; virtual ~callable_base() {} }; template <typename F> struct callable : callable_base { F functor; callable(F functor) : functor(functor) {} virtual int operator()(double d) { return functor(d); } };
Here, std::function holds a unique_ptr to a base callable_base type. For each unique functor used, a derived type callable
Copies of std::function trigger copies of the internal callable object, rather than sharing the state. This is evident from a test where the value of a mutable captured variable is incremented:
int value = 5; std::function<void()> f1 = [=]() mutable { std::cout << value++ << '\n'; }; std::function<void()> f2 = f1; // Prints 5 f1(); // Prints 5 (copy of mutable state) f2();
Thus, std::function efficiently wraps callables of varying sizes using type-erasure and heap allocation. Heap allocations are used to instantiate dynamic types based on the wrapped callable, ensuring a fixed size for std::function itself.
The above is the detailed content of How Does `std::function` Achieve Fixed Size Despite Wrapping Callables of Varying Sizes?. For more information, please follow other related articles on the PHP Chinese website!