Explorer l'implémentation de std::function
Dans le monde des expressions lambda, la notion de taille devient fluide, car elles sont essentiellement enveloppé dans des classes avec des références de taille variable. Cependant, std::function exige une taille fixe. Cela soulève la question : comment cela est-il réconcilié ?
La réponse réside dans l'effacement des caractères. Imaginons une implémentation simplifiée :
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); } };
Dans cette approche simpliste, std::function stocke un pointeur unique vers une classe de base. Pour chaque foncteur distinct, un type dérivé est créé et instancié dynamiquement. Ainsi, std::function reste de taille constante tout en s'adaptant à une gamme de foncteurs sur le tas.
Les techniques d'optimisation affinent davantage ce schéma, en utilisant des optimisations de petits objets, en évitant l'indirection, etc. Cependant, sur le plan conceptuel, l'idée de base reste la même.
Concernant les copies de std::function, les preuves expérimentales suggèrent des copies indépendantes de l'objet appelable. Un exemple artificiel :
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) }
La sortie indique des copies isolées plutôt qu'un état partagé, car les différentes invocations incrémentent la valeur indépendamment.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!