Question sur les temporaires

Le problème exposé dans ce sujet a été résolu.

Bonjour… Ce sujet est en relation avec un autre sujet que j’avais récemment posté sur le forum et intitulé Question sur les references, sujet dont laquelle j’ai commis l’erreur de le mettre résolu prématurément (car je pensais naïvement saisie toute l’étendu des explications de @gbdivers). Ainsi en créant ce nouveau sujet, je ne voulais pas mettre non-résolu puis poser la question apres mettre résolu…

Je vais d’abord exposer ma compréhension ainsi vous pouvez me corriger plus efficacement et en retour espérer que j’obtiens une réponse complète.
Bref, Il existe encore certaine ambiguïté quant a la différence entre une variable locale et un temporaire. Voici les reformulations que j’ai noté en relisant ces explications :

  1. Un temporaire est toujours de type constant;
  2. Par défaut un temporaire a la durée de vie de l’expression et de ses sous-expressions : autrement dit il a la durée de vie de l’instruction et des sous-instructions (comme le cas d’une fonction);
  3. Il est impossible de faire la conversion implicite d’un const vers un non const;
  4. Si un temporaire est capturé dans une reference, sa durée de vie est étendue a celle de la reference.

Et voici d’autres notes qui ne sont pas en relation avec les explications :

  • Une variable locale est une variable qui ne peut être utilisée que dans la fonction ou bloc dont elle est définie. Autrement toute variable déclarée dans une quelconque fonction, meme dans la fonction main, est une variable locale;
  • Ainsi sa durée de vie est relatif a la fonction/bloc : quand la fonction/bloc se termine, elle disparaît;
  • Et peut-être déclarer comme constante ou non.

Je conclus donc qu’un temporaire est normalement limitée a l’expression (instruction) et sous-expressions (sous-instructions) et qu’il est toujours constant alors qu’une variable locale est limitée a la fonction/bloc dont elle est définie et peut être soit constant ou non (différence entre temporaire et variable locale).

#include <iostream>

void fonction (int const & c)
{
    std::cout << c << std::endl;
}
int main ()
{
    int const a { 0 }; // variable locale constante
    std::cout << a << std::endl; // existe tant que la fonction main n'est pas terminee


    int b { 1 }; // variable locale non-constante
    std::cout << b << std::endl; // existe tant que la fonction main n'est pas terminee

    fonction (1234); // temporaire implicitement constant et sa duree limitee ligne 16 et 5

    return 0;
}

Les explications @gbdivers ci-dessous font reference au code suivant :

#include <iostream>

int fonction ()
{
    int variable { 10 };
    return variable;
}

int main ()
{
    int const & reference_variable { fonction () };
    std::cout << reference_variable << std::endl;

    return 0;
}
int const & reference_variable { fonction () }; // #1
std::cout << reference_variable << std::endl; // #2

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.

gbdivers

La fonction

fonction ();

ne renvoie pas un temporaire puisque sa valeur de retour n’est pas de type constant (or un temporaire est tjr de type constant). Mais en lisant cette partie de l’explication et en les confrontant aux notes, j’observe une contradiction… Je pense que cette contradiction est du a une mauvaise compréhension de ma part.Donc je vous laisse le soin de m’expliquer mon erreur.

Et enfin, y’a t-il des cas ou il y a confusion entre variable locale et temporaire ? par exemple dans le cas du code suivant :

#include <iostream>

int main ()
{
    int const a { 0 };
    std::cout << a << std::endl;

    return 0;
}

peut-on dire que la variable a,

int const a { 0 };

est a la fois temporaire (puisqu’elle est constante) et locale (puisqu’elle est limitee au bloc main)

???

+1 -0

or un temporaire est tjr de type constant

Je pense que ton incompréhension part de là. Un objet temporaire n’est pas nécessairement constant (et par défaut il ne l’est pas d’ailleurs), et une variable constante n’est pas non plus nécessairement temporaire.

Un [objet] temporaire (constant ou non) c’est une variable qui n’est pas nommée dans le code, elle est censé vivre et mourir dans la même instruction (sauf dans le cas exceptionnel que t’explique @gbdivers).

Ta variable a n’est pas temporaire : elle a un nom et une durée de vie qui va jusqu’à la fin du bloc.

+2 -0

Je pense que cette contradiction est du a une mauvaise compréhension de ma part.

amalure

Non, au contraire, tu as bien compris qu’il y a un truc qui ne va pas dans mes explications. Au lieu de "temporaire", il fallait lire "littérale". Je suis allé trop vite dans mes explications et j’ai fait cette erreur. J’ai corrigé mon message dans l’autre discussion.

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).

gbdivers

Pour le reste, comme le dit germinolegrand, être constant n’implique pas d’être temporaire.

+1 -0

Mais je ne comprends tjr pas pourquoi

int const & reference_variable { fonction () };

La fonction fonction () devrait retourner un temporaire puisqu’il apparaît qu’un temporaire est une variable qui n’est pas nommée dans le code. Or cette fonction retourne la valeur d’une variable bien nommée (dans nommer je comprends définie) :

int fonction ()
{
    int variable { 10 };
    return variable;
}
+0 -0

Hors sujet : le fait que tu expliques en détail ton raisonnement et ce que tu as compris est vraiment une bonne chose pour améliorer nos explications. (Beaucoup se contentent d’un "j’ai pas compris"). Merci pour cela.

Hors sujet 2 : les explications qu’on te donne sont des simplifications. Il faut savoir que la norme du C++ (le document qui décrit le langage) est beaucoup plus rigoureux… et donc beaucoup plus complexe. Par exemple, ce dont on parle ici correspond aux catégories de valeurs. Je te laisse jeter un coup d’oeil sur la doc : Value categories. Tout ça pour dire que les détails arrivent progressivement dans le cours, il ne faut pas t’inquiéter de ne pas comprendre tous les détails tout de suite.


Pour en revenir a :

int const & reference_variable { fonction () };

Dans ce code, ce qu’il faut comprendre, c’est que fonction() est une expression qui doit être évaluée pour initialiser la variable reference_variable. C’est comme si on avait le code équivalent :

temporaire = fonction();
int const & reference_variable { temporaire  };

Peu importe que fonction() contienne une variable. La variable variable n’est pas le temporaire retourné par la fonction fonction().


Pour entrer encore un peu plus dans les explications, cela peut paraître étrange d’avoir un return variable; dans la fonction function() et que pourtant cette variable variable ne soit pas le temporaire retourné par la fonction.

Ce qu’il faut savoir, c’est que lors qu’une fonction est appelée, elle est exécutée dans son propre "espace mémoire". Il y a un mécanisme "interne" qui va créer un espace mémoire dédié a cette fonction, qui va envoyer les paramètres d’entrée et lancer l’exécution de la fonction. Et quand l’exécution de la fonction est finie, l’espace mémoire est libéré et le retour de la fonction est renvoyé a la fonction appelante.

(Tu peux regarder la page Wikipedia Pile d’exécution.)

Une petite illustration de mon ancien cours :

void h() {
    double x {};
    double y {};
    double z {};
}
 
void g() {
    bool a {};
    bool b {};
    bool c {};
    h();
}
 
void f() {
    int i {};
    int j {};
    int k {};
    g();
}
La Pile
La Pile

Ce fonctionnement implique que lorsque la fonction fonction() se termine, son espace mémoire est libérer et la variable variable n’existe plus en mémoire. Donc cette variable n’est plus disponible et ne peut pas être la valeur retournée par la fonction. D’où le fait qu’un temporaire est créée et qui contient la valeur de variable.

IL y a 2 autres implications (que tu as déjà vu) a ce mécanisme :

  • les variables locales sont toujours correctement détruites lors que leur emplacement mémoire est libérer. Et ca, c’est cool.
  • il ne faut jamais renvoyer une référence sur une variable locale, puisque cette variable n’existera plus en dehors de la fonction.
+4 -0

Oui cppreference est vraiment très difficile a lire pour le débutant que je suis, c’est pourquoi votre pédagogie et vos explication a la fois détaillées et simplifiées m’aident bcp et je vous remercie pour ça et d’avoir pris la peine de me faire comprendre…

D’accord je vais essayer de suivre le rythme progressif de ce cours…

Je comprends mtn pourquoi la fonction fonction () retourne un temporaire : un temporaire qui contient la valeur de variable est créer et retourner car variable n’existe pas puisque l’espace mémoire dédié a fonction est libérer lorsque la fonction finie son exécution. Mais je vais relire plus en détail ce mécanisme de la pile… Si j’ai des questions sur ça, je viendrais vers vous […]

+0 -0
Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte