Exploring the Implementation of std::function
In the world of lambda expressions, the notion of size becomes fluid, as they're essentially wrapped in classes with variable-sized references. However, std::function demands a fixed size. This begs the question: how is this reconciled?
The answer lies in type-erasure. Let's envision a simplified implementation:
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); } }; class function_int_double { std::unique_ptr<callable_base> c; public: template <typename F> function(F f) { c.reset(new callable<F>(f)); } int operator()(double d) { return c(d); } };
In this simplistic approach, std::function stores a unique pointer to a base class. For each distinct functor, a derived type is created and dynamically instantiated. Thus, std::function remains constant in size while accommodating a range of functors on the heap.
Optimization techniques further refine this scheme, using small object optimizations, avoiding indirection, and the like. However, conceptually, the core idea remains the same.
Concerning copies of std::function, experimental evidence suggests independent copies of the callable object. A contrived example:
int main() { int value = 5; typedef std::function<void()> fun; fun f1 = [=]() mutable { std::cout << value++ << '\n' }; fun f2 = f1; f1(); // prints 5 fun f3 = f1; f2(); // prints 5 f3(); // prints 6 (copy after first increment) }
The output indicates isolated copies rather than shared state, as the different invocations increment the value independently.
The above is the detailed content of How Does std::function Maintain a Fixed Size Despite Handling Variable-Sized Lambda Expressions?. For more information, please follow other related articles on the PHP Chinese website!