Si vous voulez de la performance, passez par valeur si vous la stockez.
Supposons que vous ayez une fonction appelée "run this in the UI thread".
std::future<void> run_in_ui_thread( std::function<void()> )
qui exécute un peu de code dans le thread "ui", puis signale au future
une fois terminé. (Utile dans les cadres d'interface utilisateur où le fil d'interface utilisateur est l'endroit où vous êtes censé jouer avec les éléments de l'interface utilisateur).
Nous avons deux signatures que nous envisageons :
std::future<void> run_in_ui_thread( std::function<void()> ) // (A)
std::future<void> run_in_ui_thread( std::function<void()> const& ) // (B)
Maintenant, nous sommes susceptibles de les utiliser comme suit :
run_in_ui_thread( [=]{
// code goes here
} ).wait();
qui créera une fermeture anonyme (un lambda), construira un fichier std::function
d'en sortir, de le passer à la run_in_ui_thread
puis attendez qu'elle finisse de s'exécuter dans le fil principal.
Dans le cas (A), le std::function
est directement construit à partir de notre lambda, qui est ensuite utilisé dans l'application run_in_ui_thread
. Le lambda est move
d dans le std::function
de sorte que tout état mobile y est efficacement transporté.
Dans le second cas, une std::function
est créé, le lambda est move
d'y entrer, alors ce temporaire std::function
est utilisé par référence dans le run_in_ui_thread
.
Jusqu'à présent, tout va bien, les deux se comportent de manière identique. Sauf que le run_in_ui_thread
va faire une copie de son argument de fonction pour l'envoyer au thread de l'interface utilisateur pour l'exécuter ! (il reviendra avant d'avoir terminé, il ne peut donc pas simplement utiliser une référence à cette fonction). Pour le cas (A), nous avons simplement move
le site std::function
dans son stockage à long terme. Dans le cas (B), nous sommes obligés de copier le fichier std::function
.
Ce magasin rend le passage par valeur plus optimal. S'il y a la moindre possibilité que vous stockiez une copie du fichier std::function
, passe par valeur. Sinon, les deux méthodes sont à peu près équivalentes : le seul inconvénient de la méthode by-value est que vous prenez le même encombrant std::function
et faire en sorte qu'une sous-méthode après l'autre l'utilise. En dehors de cela, une move
sera aussi efficace qu'un const&
.
Maintenant, il y a d'autres différences entre les deux, qui se manifestent surtout si nous avons un état persistant dans le fichier std::function
.
Supposons que le std::function
stocke un objet avec un operator() const
mais il a aussi des mutable
les membres des données qu'il modifie (quelle impolitesse !).
Dans le std::function<> const&
l'affaire, le mutable
Les membres de données modifiés se propageront hors de l'appel de fonction. Dans le std::function<>
Dans ce cas, ils ne le feront pas.
Il s'agit d'un cas particulier relativement étrange.
Vous voulez traiter std::function
comme vous le feriez pour n'importe quel autre type de document lourd et peu coûteux à déplacer. Le déplacement est bon marché, la copie peut être coûteuse.