Outils d'utilisateurs

Outils du Site


rvalue_et_lvalue

Différences

Cette page vous donne les différences entre la révision choisie et la version actuelle de la page.

Lien vers cette vue

rvalue_et_lvalue [2015/10/14 01:35]
gbdivers
rvalue_et_lvalue [2019/02/08 05:29] (Version actuelle)
anthonyholstein
Ligne 1: Ligne 1:
  
-^ [[ratio|Chapitre précédent]] ^ [[programmez_avec_le_langage_c|Sommaire principal]] ^ [[inference_de_type|Chapitre suivant]] ^+^ [[ratio|Chapitre précédent]] ^ [[programmez_avec_le_langage_c|Sommaire principal]] ^ [[enum_class|Chapitre suivant]] ^ 
 + 
 +__ ajouter l'operateur comma et la declaration de plusieurs variables __
  
 ====== Utiliser la mémoire avec les variables ====== ====== Utiliser la mémoire avec les variables ======
Ligne 78: Ligne 80:
     int x { 123 };     int x { 123 };
     int y { 456 };     int y { 456 };
-    int { 789 };+    int { 789 };
     std::cout << x << std::endl;     std::cout << x << std::endl;
     std::cout << y << std::endl;     std::cout << y << std::endl;
Ligne 111: Ligne 113:
  
 Vous rencontrez probablement ce type de syntaxe dans des codes existants, par exemple dans des tutoriels en ligne ou dans des livres. Ce cours se focalise sur les syntaxes recommandées en C++ moderne, ces syntaxes ne seront donc pas détaillées par la suite. Mais vous apprendrez sans problème ces syntaxes dans les exercices d'apprentissage que vous réaliserez. Vous rencontrez probablement ce type de syntaxe dans des codes existants, par exemple dans des tutoriels en ligne ou dans des livres. Ce cours se focalise sur les syntaxes recommandées en C++ moderne, ces syntaxes ne seront donc pas détaillées par la suite. Mais vous apprendrez sans problème ces syntaxes dans les exercices d'apprentissage que vous réaliserez.
 +
 +Attention, il existe une variante de ces syntaxes, qui peut sembler correcte :
 +
 +<code cpp>
 +int x();
 +</code>
 +
 +Mais cette syntaxe ne permet pas du tout de déclarer une variable (cela déclare une fonction). On voit régulièrement des débutants reproduire cette erreur.
 </note> </note>
  
Ligne 116: Ligne 126:
 ==== Modifier la valeur d'une variable ==== ==== Modifier la valeur d'une variable ====
  
-L'intérêt d'une variable est que vous allez pouvoir la réutiliser dans des expressions. chaque fois qu'une expression contenant une variable est évaluée, la variable est remplacé par sa valeur lors du calcul.+<note warning>**Regle fondamentale** 
 + 
 +Il ne faut jamais modifier plusieurs fois une meme variable dans une ligne de code ! L'ordre d'evaluation n'est pas fixe et le comportement n'est pas definie. 
 + 
 +Par exemple : 
 + 
 +<code cpp> 
 +std::cout << ++i << ++i << std::endl; 
 +</code> 
 + 
 +Ce code modifie deux fois la variable ''i'' dans la meme ligne, ce qui produit un comportement indetermine. 
 + 
 +Note : la vraie regle est un peu plus compliquee, mais retenez cette version simple pour le moment. 
 +</note> 
 + 
 +L'intérêt d'une variable est que vous allez pouvoir la réutiliser dans des expressions. À chaque fois qu'une expression contenant une variable est évaluée, la variable est remplacée par sa valeur lors du calcul.
  
 <code cpp main.cpp> <code cpp main.cpp>
Ligne 193: Ligne 218:
 De plus, dans les syntaxes alternatives, il est possible d'écrire le code suivant pour créer une variable. De plus, dans les syntaxes alternatives, il est possible d'écrire le code suivant pour créer une variable.
  
-<code>+<code cpp>
 int x = 123; // initialisation int x = 123; // initialisation
     x = 456; // affectation     x = 456; // affectation
Ligne 203: Ligne 228:
 </note> </note>
  
-Dans de nombreux cas, vous n'aurez pas besoin de modifier la valeur d'une variable. Dans ce cas, on parle de constante. Pour indiquer cela dans le code, vous pouvez utiliser le mot-clé ''const'' (//constant//) devant le type de la variable lors de l'initialisation. De plus, cela permet au compilateur de vérifier que vous ne modifier effectivement pas cette variable et de réaliser certaines optimisations.+Dans de nombreux cas, vous n'aurez pas besoin de modifier la valeur d'une variable. Dans ce cas, on parle de constante. Pour indiquer cela dans le code, vous pouvez utiliser le mot-clé ''const'' (//constant//) devant le type de la variable lors de l'initialisation. De plus, cela permet au compilateur de vérifier que vous ne modifiez effectivement pas cette variable et de réaliser certaines optimisations.
  
 <code cpp main.cpp> <code cpp main.cpp>
Ligne 223: Ligne 248:
 </code> </code>
  
-qui peut se traduire pas "affectation sur une variable en lecture seule".+qui peut se traduire par "affectation sur une variable en lecture seule".
  
 Il est important d'utiliser ''const'' aussi souvent que possible, c'est-à-dire à chaque fois que vous ne modifiez pas une variable. Dans la suite de ce cours, nous utiliserons systématiquement ''const'' dans les codes d'exemple. Il est important d'utiliser ''const'' aussi souvent que possible, c'est-à-dire à chaque fois que vous ne modifiez pas une variable. Dans la suite de ce cours, nous utiliserons systématiquement ''const'' dans les codes d'exemple.
Ligne 229: Ligne 254:
 <note>**Position de ''const''** <note>**Position de ''const''**
  
-Le mot-clé ''const'' peut se placer avant ou après le type. Selon sa position, cela peut changer l'interprétation de ce qui est constant et de ce qui ne l'est pas. Mais dans les cas simple présenté ici, la position ne change rien à la signification de ''const''. Les codes d'exemple utiliseront indifféremment l'une ou l'autre écriture.+Le mot-clé ''const'' peut se placer avant ou après le type. Selon sa position, cela peut changer l'interprétation de ce qui est constant et de ce qui ne l'est pas. Mais dans les cas simples présentés ici, la position ne change rien à la signification de ''const''. Les codes d'exemple utiliseront indifféremment les deux écritures.
  
-<code>+<code cpp>
 const int i { 123 }; const int i { 123 };
 int const j { 456 }; int const j { 456 };
 </code> </code>
  
-La position de ''const'' sera importante dans certains cas, comme par exemple les pointeurs, qui seront vu à la fin de ce cours.+La position de ''const'' sera importante dans certains cas, comme par exemple les pointeurs, qui seront vus à la fin de ce cours. 
 + 
 +Cependant, il est parfois facile de manquer le mot-clé ''const'' lorsqu'il est placé après le type. 
 + 
 +<code cpp> 
 +unsigned short int const i { 12 }; 
 +unsigned int j { 3456 }; 
 +std::vector<long int> const v { 1, 2, 3 }; 
 +std::vector<int> w { 4 }; 
 +</code> 
 + 
 +Dans ce cas, vous pouvez placer le mot-clé ''const'' avant le type ou jouer avec la présentation du code pour le rendre plus évident. (L'utilisation des espaces est libre en C++.) 
 + 
 +<code cpp> 
 +unsigned shot int     const i {      12 }; 
 +unsigned int                j {    3456 }; 
 +std::vector<long int> const v { 1, 2, 3 }; 
 +std::vector<int>            w {       4 }; 
 +</code> 
 </note> </note>
  
Ligne 254: Ligne 298:
  
 En C++, les types de base s'écrivent avec des mots-clés définis dans le langage. Vous avez vu que le type ''int'' correspond aux entiers. Il existe beaucoup de types définis en C++ (et il est possible de définir ses propres types, il peut donc potentiellement exister une infinité de types différents), mais retenez pour le moment les types correspondants aux littérales que vous avez déjà manipulées : En C++, les types de base s'écrivent avec des mots-clés définis dans le langage. Vous avez vu que le type ''int'' correspond aux entiers. Il existe beaucoup de types définis en C++ (et il est possible de définir ses propres types, il peut donc potentiellement exister une infinité de types différents), mais retenez pour le moment les types correspondants aux littérales que vous avez déjà manipulées :
-}+
   * ''int'' (abréviation de //integer//, "entier" français) correspond à un nombre entier ;   * ''int'' (abréviation de //integer//, "entier" français) correspond à un nombre entier ;
   * ''double'' correspond à un nombre réel (vous verrez par la suite pourquoi le C++ utilise ce terme) ;   * ''double'' correspond à un nombre réel (vous verrez par la suite pourquoi le C++ utilise ce terme) ;
Ligne 261: Ligne 305:
   * ''bool'' correspond aux booléens.   * ''bool'' correspond aux booléens.
  
-Il existe également des mots-clés permettant de modifier un type de base. Par exemple, ''signed'' et ''unsigned'' permettent respectivement de spécifier un type **entier** signée (qui accepte des valeurs négatives et positives) et non-signée (qui acceptent uniquement des valeurs positives).+Il existe également des mots-clés permettant de modifier un type de base. Par exemple, ''signed'' et ''unsigned'' permettent respectivement de spécifier un type **entier** signé (qui accepte des valeurs négatives et positives) et non-signé (qui accepte uniquement des valeurs positives).
  
 <code cpp> <code cpp>
Ligne 323: Ligne 367:
 Un message d'erreur "type 'double' cannot be narrowed to 'int'" ("le type 'double' ne peut pas être restreint en type 'int'") indique que la conversion de types peut produire une perte d'information, c'est a dire que le type ''double'' peut contenir des valeurs que le type ''int'' ne peut pas contenir. Un message d'erreur "type 'double' cannot be narrowed to 'int'" ("le type 'double' ne peut pas être restreint en type 'int'") indique que la conversion de types peut produire une perte d'information, c'est a dire que le type ''double'' peut contenir des valeurs que le type ''int'' ne peut pas contenir.
  
-Une note permet d'aider le développeur corriger ce problème : "insert an explicit cast to silence this issue" ("insérer une conversion explicite pour faire taire ce problème").+Une note permet d'aider le développeur à corriger ce problème : "insert an explicit cast to silence this issue" ("insérer une conversion explicite pour faire taire ce problème").
  
 Le message suivant est un avertissement : "implicit conversion (...) changes value from 1.2 to 1" ("la conversion implicite change la valeur 1.2 en 1"). Sans surprise, puisque les types ne sont pas directement convertibles sans perte potentielle d'information, les valeurs doivent être arrondies (dans ce cas "1.2" en "1"). Le message suivant est un avertissement : "implicit conversion (...) changes value from 1.2 to 1" ("la conversion implicite change la valeur 1.2 en 1"). Sans surprise, puisque les types ne sont pas directement convertibles sans perte potentielle d'information, les valeurs doivent être arrondies (dans ce cas "1.2" en "1").
Ligne 348: Ligne 392:
 En fait, pour des raisons historiques, le type ''char'', qui représente un caractère, est considéré comme un type entier et peut donc être converti automatiquement par le compilateur (conversion implicite). La valeur 49 correspond au caractère ''1'' dans la norme [[https://fr.wikipedia.org/wiki/American_Standard_Code_for_Information_Interchange|ASCII]]. En fait, pour des raisons historiques, le type ''char'', qui représente un caractère, est considéré comme un type entier et peut donc être converti automatiquement par le compilateur (conversion implicite). La valeur 49 correspond au caractère ''1'' dans la norme [[https://fr.wikipedia.org/wiki/American_Standard_Code_for_Information_Interchange|ASCII]].
  
-Généralement, la conversion de ''char'' en ''int'' ne posera pas de problème, mais dans d'autres cas, ce type de conversion implicite peut réellement produire des comportements non prévus par le développeur et être assez difficile identifier et corriger.+Généralement, la conversion de ''char'' en ''int'' ne posera pas de problème, mais dans d'autres cas, ce type de conversion implicite peut réellement produire des comportements non prévus par le développeur et être assez difficile à identifier et corriger.
  
 **Conversion impossible** **Conversion impossible**
  
-La ligne [4] produit un message d'erreur plus simple : "cannot initialize a variable of type 'int' with an lvalue of type 'const char [2]'" (impossible d'initialiser une variable de type ''int'' avec une lvalue de type ''const char [2]''). Le compilateur ne sait pas convertir une chaîne de caractères en entier et le signal.+La ligne [4] produit un message d'erreur plus simple : "cannot initialize a variable of type 'int' with an lvalue of type 'const char [2]'" (impossible d'initialiser une variable de type ''int'' avec une lvalue de type ''const char [2]''). Le compilateur ne sait pas convertir une chaîne de caractères en entier et le signale.
  
 Cela peut sembler ennuyeux que le compilateur bloque le processus, on aimerait parfois qu'il se débrouille pour trouver une solution et réussisse toujours a créer le programme. Mais il faut bien comprendre que c'est en fait une aide, pas une punition. Il est préférable que le compilateur dise "je ne sais pas, aide moi", plutôt que suivre un comportement que le développeur n'a pas prévu. Cela peut sembler ennuyeux que le compilateur bloque le processus, on aimerait parfois qu'il se débrouille pour trouver une solution et réussisse toujours a créer le programme. Mais il faut bien comprendre que c'est en fait une aide, pas une punition. Il est préférable que le compilateur dise "je ne sais pas, aide moi", plutôt que suivre un comportement que le développeur n'a pas prévu.
Ligne 404: Ligne 448:
   * ''variable_réelle'' : contient un caractère interdit (''é'').   * ''variable_réelle'' : contient un caractère interdit (''é'').
  
-<note>Un identifiant qui commence par un tiret bas, comme ''_une_variable'', est en fait autorisé par la norme C++, mais son usage est restreint. Pour éviter les problèmes, il est d'usage de ne pas utiliser ce type d'identifiant.</code>+<note>Un identifiant qui commence par un tiret bas, comme ''_une_variable'', est en fait autorisé par la norme C++, mais son usage est restreint. Pour éviter les problèmes, il est d'usage de ne pas utiliser ce type d'identifiant.</note>
  
 Comme vous le voyez, le langage C++ laisse de grandes libertés pour choisir un identifiant… ce qui peut poser des problèmes. Exemple de mauvais identifiant : Comme vous le voyez, le langage C++ laisse de grandes libertés pour choisir un identifiant… ce qui peut poser des problèmes. Exemple de mauvais identifiant :
Ligne 466: Ligne 510:
 ===== Portée d'une variable ===== ===== Portée d'une variable =====
  
-Une variable existe à partir du moment où elle est déclaration et jusqu'à la fin du bloc contenant sa déclaration. Cela s'appelle la portée de la variable. Utiliser une variable avant de l'avoir définie produit donc une erreur.+Une variable existe à partir du moment où elle est déclarée et jusqu'à la fin du bloc contenant sa déclaration. Cela s'appelle la portée de la variable. Utiliser une variable avant de l'avoir définie produit donc une erreur.
  
 <code cpp main.cpp> <code cpp main.cpp>
Ligne 523: Ligne 567:
  
 Il faut bien comprendre ce qui se passe ici. Une première variable nommée ''x'' est créée dans le premier bloc et initialisée avec la valeur 123. Puis celle-ci est détruite à la fin du bloc et une nouvelle variable est créée. Cette variable s'appelle aussi ''x'', mais c'est bien une variable différente. Il faut bien comprendre ce qui se passe ici. Une première variable nommée ''x'' est créée dans le premier bloc et initialisée avec la valeur 123. Puis celle-ci est détruite à la fin du bloc et une nouvelle variable est créée. Cette variable s'appelle aussi ''x'', mais c'est bien une variable différente.
 +
 +<note>**Durée de vie (lifetime)**
 +
 +Une autre notion importante concernant les objets, c'est la durée de vie. Celle-ci est simplement le temps entre le moment où un objet est crée en mémoire et le moment où cet objet est libérée. Essayez d'utiliser un objet qui n'est pas disponible en mémoire va provoquer au mieux un crash du programme, voire pire. Dans tous les cas, cela sera un comportement indéfini (//Undefined Behavior//).
 +
 +Il existe plusieurs types de variables (dynamique, statique, etc), mais pour le moment, vous n'avez vu que les variables locales, dans ce chapitre. Dans cette situation, la durée de vie peut être confondue avec la portée (ce n'est pas tout a fait vrai, mais vous verrez cela plus tard, dans le chapitre sur la Pile) : 
 +
 +**Un objet est crée en mémoire lorsqu'une variable locale est déclarée dans le code et il est détruit lorsque la variable sort de sa portée.**
 +
 +On parle parfois de "variable automatique", du fait que l'objet est détruit automatiquement. Mais cette appellation n'est pratiquement plus utilisée, on parle simplement de "variable locale".
 +
 +Notez bien la distinction entre le concept de "variable", qui concerne le code avant compilation, et le concept "d'objet", qui concerne la mémoire pendant l’exécution du programme.</note>
  
  
  
-^ [[ratio|Chapitre précédent]] ^ [[programmez_avec_le_langage_c|Sommaire principal]] ^ [[inference_de_type|Chapitre suivant]] ^+^ [[ratio|Chapitre précédent]] ^ [[programmez_avec_le_langage_c|Sommaire principal]] ^ [[enum_class|Chapitre suivant]] ^
rvalue_et_lvalue.1444779305.txt.gz · Dernière modification: 2015/10/14 01:35 par gbdivers