Il était autrefois généralement recommandé1 de utiliser pass by const ref pour tous les types, sauf pour les types primitifs (char
, int
, double
, etc.), pour les itérateurs et pour les objets fonctionnels (lambdas, classes dérivant de std::*_function
).
C'était particulièrement vrai avant l'existence des sémantiques de déplacement. La raison est simple: si vous passiez par valeur, une copie de l'objet devait être faite et, sauf pour les objets très petits, cela est toujours plus coûteux que de passer une référence.
Avec C++11, nous avons gagné les sémantiques de déplacement. En un mot, les sémantiques de déplacement permettent que, dans certains cas, un objet peut être passé "par valeur" sans le copier. En particulier, c'est le cas lorsque l'objet que vous passez est un rvalue.
En soi, déplacer un objet est toujours au moins aussi coûteux que passer par référence. Cependant, dans de nombreux cas, une fonction copiera de toute façon un objet internement - c'est-à-dire qu'elle prendra la possession de l'argument.2
Dans ces situations, nous avons le compromis (simplifié) suivant:
- Nous pouvons passer l'objet par référence, puis copier internement.
- Nous pouvons passer l'objet par valeur.
"Passer par valeur" cause toujours la copie de l'objet, sauf si l'objet est un rvalue. Dans le cas d'un rvalue, l'objet peut être déplacé au lieu d'être copié, de sorte que le deuxième cas n'est soudainement plus "copier, puis déplacer" mais "déplacer, puis (potentiellement) déplacer à nouveau".
Pour les grands objets qui implémentent des constructeurs de déplacement adéquats (comme des vecteurs, des chaînes de caractères ...), le deuxième cas est alors nettement plus efficace que le premier. Par conséquent, il est recommandé de utiliser le passage par valeur si la fonction prend la possession de l'argument, et si le type d'objet prend en charge un déplacement efficace.
Une note historique:
En fait, n'importe quel compilateur moderne devrait être capable de comprendre quand le passage par valeur est coûteux, et convertir implicitement l'appel pour utiliser une const ref si possible.
En théorie. En pratique, les compilateurs ne peuvent pas toujours changer cela sans rompre l'interface binaire de la fonction. Dans certains cas spéciaux (lorsque la fonction est inlinée), la copie sera en fait éliminée si le compilateur peut comprendre que l'objet original ne sera pas modifié par les actions dans la fonction.
Mais en général, le compilateur ne peut pas déterminer cela, et l'avènement des sémantiques de déplacement en C++ a rendu cette optimisation beaucoup moins pertinente.
1 Par exemple, dans Scott Meyers, Effective C++.
2 Cela est particulièrement souvent vrai pour les constructeurs d'objets, qui peuvent prendre des arguments et les stocker internement pour faire partie de l'état de l'objet construit.
0 votes
Correspondant : stackoverflow.com/questions/2139224/…