A vrai dire, je réagissais surtout à
car je suis désolé, mais, conceptuellement parlant, il n'y a absolument rien qui justifie de l'interdire...Quand un étudiant me montre une copie constante, je le renvois illico. Soit il fait une copie et il assume et il sait le justifier. Soit il fait une const&.
En effet, reprenons tout depuis le début et revenons un tout petit peu aux "basiques" (je sais, tu les connais déjà depuis longtemps ):
Un paramètre de fonction correspond à une donnée pour laquelle la fonction appelée est incapable de définir une valeur (un état) par elle-même.A quoi sert un paramètre pour une fonction
Le paramètre en question a pour résultat de déclarer une variable du type et du nom indiqué accessible au sein de la fonction.
La notion de référence nous permet essentiellement de faire en sorte que les modifications éventuelles apportées par la fonction appelée au paramètre transmis par référence soient répercutées sur la variable qui a servi d'argument dans la fonction appelante. Accessoirement, le passage par référence permet d'éviter le phénomène de copie lié au passage par valeurA quoi sert la notion de référence
Note que j'aurais pu énoncer les choses sous un point de vue différent :
La notion de référence nous permet de transmettre une variable comme argument lors de l'appel d'une fonction en éitant le phénomène de copie de cette variable au niveau de la fonction appelée. Elle présente néanmoins "l'effet secondaire" de faire en sorte que toute modification apportée au paramètre transmis par référence au niveau de la fonction appelée sera répercutée sur la variable qui a servi d'argument au niveau de la fonction appelante.
La constante permet d'indiquer explicitement au compilateur qu'il doit veiller à ne pas autoriser la modification de la variable (au sens le plus large possible) auquel elle se rapporte.A quoi sert la constante
Cela impose un "contrat" que le compilateur est parfaitement en mesure de faire respecter : la variable ne peut en aucun cas être modifiée.
Maintenant que nous avons repris nos basiques, réfléchissons un peu au différentes combinaisons :
Variable et constante :
Il n'y a absolument rien qui t'interdise de déclarer une variable locale comme étant constante : cela ne fait rien d'autre que la transformer en "constante locale" : Je n'aurais, par exemple, aucun problème avec l'idée d'écrire un code proche de
A vrai dire, j'y verrais même deux avantages :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14 /* Fonction lisant 10 fichiers dont seul le suffixe est différent */ void foo(){ std::string const base{"chemin/vers/fichier"}; std::string const ext{".ext"}; for(int i=1;i<11;++i){ std::string filename(base); filename.append(std::to_string(i) .append(ext); std::ifstream ifs(filename); if(ifs){ /* ... */ } } }
Primo : j'indique explicitement au lecteur du code que les chaines de caractères base et ext n'ont pas vocation à être modifiée
Secundo : Je m'assure que le compilateur m'engueulera si, à un moment ou à un autre, je venais à essayer de modifier la valeur de ces chaines de caractères.
référence et constante?
Avant de nous intéresser à la raison qui nous poussera à transmettre un paramètre sous la forme d'une référence constante, intéressons nous aux raisons qui nous pousseront à transmetre un paramètre sous la forme d'une référence (non constante):
On peut décider de le faire pour deux raisons :
- Soit parce que l'on souhaite effectivement que les modifications appliquées au paramètre dans la fonction appelée soient répercutées à la fonction dans la fonction appelante. D'une certaine manière, le fait que l'on évite également la copie de l'argument n'est à considérer que comme un "bonus supplémentaire"
- Soit parce que l'on souhaite effectivement éviter le phénomène de copie lié au passage par valeur. Le fait que les modifications appliquées au paramètre dans la fonction appelée soient répercutées sur l'argument utilisé dans la fonction appelante est alors considéré un "effet secondaire potentiellement non souhaitable".
D'une certaine manière, le passage par référence constante n'aura réellement du sens que si cet effet secondaire n'est ni souhaitable ni souhaité.
valeur constante?
La constante en elle-même n'indique qu'une seule chose : la fonction appelée ne peut pas modifier la variable correspondante. Le fait que l'on passe le paramètre par valeur au lieu de le passer par référence semble indiquer qu'il y aura copie. Mais la question est "le passage par référence constante évitera-t-il effectivement qu'il n'y ait construction (par copie ou non) d'une variable locale à la fonction appelée "
La réponse à cette question est, malheureusement, non...
Reprenons la fonction que je présentais en exemple, et modifions la de manière à faire en sorte qu'elle accepte un paramètre indiquant le chemin à suivre pour accéder au fichier sous une forme proche de
Le passage par référence constante est sensé éviter la création d'une copie, c'est à dire que nous l'éviterons si on appelle cette fonction sous une forme proche de
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14 void foo(std::string const & path){ std::string const base{"fichier"}; std::string const ext{".ext"}; for(int i=1;i<11;++i){ std::string filename(base); filename.append(path) .append(std::to_string(i) .append(ext); std::ifstream ifs(filename); if(ifs){ /* ... */ } } }
Mais on ne peut ignorer le fait que de nombreux appels à cette fonction pourraient prendre la forme de
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 int main(){ std::string /* const */ path{"chemin/a/suivre"}; foo(path); }
Et que cela occasionnera de toutes façons la création d'une variable temporaire anonyme au niveau de la fonction appelante. A ce stade, l'intérêt du passage par référence qui est d'éviter la copie devient strictement minimal alors que celui de transmettre une valeur constante reste tout à fait capital : le compilateur nous engueulera si on essaye de modifier la valeur de ce paramètre dans la fonction appelée.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 int main(){ foo("chemin/ecrit/en/dur"); }
Je ne vois donc absolument rien qui puisse justifier d'un point de vue conceptuel de refuser un passage par valeur constante sous la forme de
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14 void foo(std::string const path){ std::string const base{"fichier"}; std::string const ext{".ext"}; for(int i=1;i<11;++i){ std::string filename(base); filename.append(path) .append(std::to_string(i) .append(ext); std::ifstream ifs(filename); if(ifs){ /* ... */ } } }
Partager