Est-ce que ce code est correcte et valide ?
Réponse simple : oui.
Réponse simple mais plus détaillée.
Je ne sais pas si ce détail très particulier sur la durée de vie des temporaires est dans le cours. Normalement, un temporaire a la durée de vie de l’expression (quand l’expression est finie, le temporaire est détruit).
Par exemple, si tu écris :
void foo(int const& i) {
std::cout << i << std::endl;
}
int main() {
foo(1234);
}
Le temporaire "1234" de la ligne #3 n’existe pas encore a la ligne #2 et sera détruit a la ligne #4. Il existe pendant l’exécution de la ligne #3 uniquement. Mais cela implique qu’il existe aussi dans les sous-expressions utilisées dans la ligne #3, en particulier l’appel de fonction "foo" et a la ligne #1.
Si on déroule linéairement l’exécution de ce code, on pourra écrire :
- exécution de ligne #2
-
exécution de la ligne #3
- exécution de la ligne #4
A la vue du mot clé const, le compilateur va créer un objet temporaire anonyme
Tout ça pour expliquer que la durée de vie du temporaire est complètement indépendant de l’utilisation de const
en fait. Le compilateur ne crée pas un temporaire parce qu’il y a const.
Par contre, le temporaire une littérale est toujours de type constant. Par exemple, la littérale 1234
sera de type int const
et pas int
. Or, il n’est pas possible de faire un cast implicit d’un const
(le temporaire) vers un non const
(une référence).
C’est pour cela que le code suivant est interdit, ce n’est pas un probleme de durée de vie du temporaire, c’est un probleme de respect des const
.
void foo(int & i);
void bar(int const& i);
int main() {
foo(1234);
bar(1234);
}
(Par contre, le passage d’une "non-référence" vers une référence est implicite, donc pas de probleme pour ca).
J’espère que la question de la durée de vie des temporaires et des const
est plus clair. Par contre, tu dois maintenant te poser la question de pourquoi le code que tu as donné est valide. Parce que si on suit ces explications, dans le code suivant :
int const & reference_variable { fonction () };
std::cout << reference_variable << std::endl;
le temporaire retourné par la fonction "fonction" a la ligne #1 ne devrait plus être valide a la ligne #2.
La raison est qu’il existe une règle supplémentaire dont je n’ai pas encore parlé (et je ne me souviens plus si elle est expliquée dans le cours) : l’extension de durée de vie des temporaires ("C++ lifetime extension of a temporary" si tu veux faire une recherche).
En gros, cette règle dit que si un temporaire est "capturé" dans une référence, sa durée de vie est étendue a la durée de vie de la référence.
Dans ton code, la référence est valide a la ligne #2, donc le temporaire est encore valide aussi.
Pour les détails (complexes) de cette règle, cf la doc : https://en.cppreference.com/w/cpp/language/reference_initialization#Lifetime_of_a_temporary
Ou bien est-ce que cela aura le meme effet qu’une copie, comme si on faisait
int variable { fonction () };
L’effet "visible" sera la même, mais les mécanismes sont très différents. Dans ce code, le temporaire est bien détruit a la fin de l’évaluation de l’expression, il n’y a pas extension de sa durée de vie. C’est un nouvel objet, non temporaire, qui est créé par copie du temporaire. Et ce nouvel objet a une durée de vie qui n’est pas limitée a l’expression.
Donc pour résumer, 3 notions importantes :
- le fonctionnement de la durée de vie des temporaires (limité la l’expression, par défaut)
- le respect des
const
(impossible de passer implicitement d’un const
vers un non const
)
- l’extension de la durée de vie des temporaires avec les références
Voila pour les explications détaillées. Si tu y vois des contractions avec les explications du cours, n’hésites pas a le dire, pour corriger mes explications ou le cours.