Pourquoi passer par référence const plutôt que par valeur?

D’après ce que j’ai compris: lorsque vous passez par valeur, la fonction crée une copie locale de l’argument passé et l’utilise; quand la fonction se termine, cela sort du cadre. Lorsque vous passez par référence const, la fonction utilise une référence à l’argument passé qui ne peut pas être modifié. Cependant, je ne comprends pas pourquoi on choisirait l’un plutôt que l’autre, sauf dans une situation où un argument doit être modifié et renvoyé. Si vous avez eu une fonction void où rien n’est renvoyé, pourquoi en choisir une sur l’autre?

EDIT: Donc, passer par référence constante évite de copier l’object. Dans quelles situations est-il bon de copier l’object? Je veux dire, pourquoi ne pas simplement utiliser les références const tout le temps si cela optimise constamment les performances?

Il y a deux considérations principales. La première est la dépense de copie de l’object passé et la seconde, les hypothèses que le compilateur peut faire lorsque l’object est un object local.

Par exemple, dans la première forme, dans le corps de f , on ne peut pas supposer que a et b ne font pas référence au même object; la valeur de a doit donc être relue après toute écriture dans b , juste au cas où. Dans la seconde forme, a ne peut pas être modifié via une écriture dans b , car il est local à la fonction, ces relectures sont donc inutiles.

 void f(const Obj& a, Obj& b) { // a and b could reference the same object } void f(Obj a, Obj& b) { // a is local, b cannot be a reference to a } 

Exemple: dans le premier exemple, le compilateur peut être en mesure de supposer que la valeur d’un object local ne change pas lorsqu’un appel non lié est effectué. Sans informations sur h , le compilateur peut ne pas savoir si un object pour lequel cette fonction a une référence (via un paramètre de référence) n’est pas modifié par h . Par exemple, cet object peut faire partie d’un état global modifié par h .

 void g(const Obj& a) { // ... h(); // the value of a might change // ... } void g(Obj a) { // ... h(); // the value of a is unlikely to change // ... } 

Malheureusement, cet exemple n’est pas en fonte. Il est possible d’écrire une classe qui, par exemple, ajoute un pointeur à un object d’état global dans son constructeur, de sorte que même un object local de type classe puisse être modifié par un appel de fonction global. Malgré cela, il existe encore potentiellement plus d’optimisations valables pour les objects locaux car elles ne peuvent pas être directement associées à des alias par des références transmises ou par d’autres objects préexistants.

Le passage d’un paramètre par référence const doit être choisi là où la sémantique des références est réellement requirejse, ou comme amélioration des performances uniquement si le coût du repliement potentiel serait compensé par les frais de copie du paramètre.

Passer des arguments par valeur et donc les copier peut être coûteux – les références const évitent cette étape coûteuse tout en promettant à l’appelant que l’object ne sera pas modifié.

Généralement, les types fondamentaux ( int , double , …) sont passés par valeur, alors que les types de classe sont passés par référence const.

Il peut toutefois y avoir des exceptions où la valeur de passage pour les types de classe peut être bénéfique.

Faire une copie d’un object peut affecter considérablement les performances dans certains cas. Considérons une fonction dont l’argument sera std::vector et que vous souhaitez transmettre au vecteur avec 1 million d’éléments. Dans ce cas, vous voudrez utiliser la référence const en passant par la valeur. Dans cette question SO, vous pouvez trouver une règle générale simple pour votre question.

Parfois, faire une copie d’un object peut coûter cher et, par conséquent, référence par référence continue évitera d’avoir à faire cette copie. Sinon, je dirais que vous devriez simplement passer par valeur si c’est ce qui est requirejs sémantiquement.

Passer un argument par valeur entraîne la surcharge d’une copie de l’object en cours de transmission à la fonction.

Peut-être qu’un object n’est pas copiable et que vos choix sont limités.

En raison des avantages de performance que vous obtiendrez. Disons que vous avez un gros object (en termes de taille en octets). Maintenant, si vous transmettez cet object par valeur à une fonction, une copie inutile doit en être créée. Cependant, vous pouvez obtenir le même effet en transmettant une référence const à cet object lui-même sans créer de copie. Puisqu’une référence est normalement stockée sous forme de pointeur sous les capots, le coût de passage d’une référence est tout simplement sizeof(pointer) .

Un tableau ne peut pas être passé par valeur, c’est donc un bon moment pour utiliser un pointeur const.

Pour éviter de faire une copie inutile , améliorant ainsi les performances.