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/02 18:53]
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 }; 
-    cout << x << endl; +    std::cout << x << std::endl; 
-    cout << y << endl; +    std::cout << y << std::endl; 
-    cout << z << endl;+    std::cout << z << std::endl;
 } }
 </code> </code>
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>
 +
 +
 +==== Modifier la valeur d'une variable ====
 +
 +<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>
 +#include <iostream>
 + 
 +int main() {
 +    int x { 123 };
 +    int y { 456 };
 +    std::cout << x * 2 << std::endl; // affiche le résultat du calcul 123 * 2
 +    std::cout << x + y << std::endl; // affiche le résultat du calcul 123 + 456
 +}
 +</code>
 +
 +affiche :
 +
 +<code>
 +246
 +579
 +</code>
 +
 +Une expression peut également être utilisée pour initialiser une autre variable.
 +
 +<code cpp main.cpp>
 +#include <iostream>
 + 
 +int main() {
 +    int x { 123 };
 +    int y { x * 2 };
 +    std::cout << y << std::endl; // affiche le résultat du calcul 123 * 2
 +}
 +</code>
 +
 +affiche :
 +
 +<code>
 +246
 +</code>
 +
 +Une variable permet donc de retenir le résultat d'un calcul complexe, qui serait pénible de devoir réécrire plusieurs fois.
 +
 +<note>**Modifier une variable**
 +
 +Une variable est définie par un type, un identifiant et une valeur. Même si pour être rigoureux, il faut dire "modifier la valeur d'une variable", on simplifie souvent en disant "modifier une variable". Il n'y a pas de confusion possible, puisque le type et l'identifiant d'une variable ne peuvent être définis que lors de la création et ne plus être modifié ensuite.
 +</note>
 +
 +Il est également possible de modifier la valeur d'une variable, en utilisant l'opérateur d'affectation ''=''. La syntaxe est la suivante :
 +
 +<code>
 +IDENTIFIANT = VALEUR;
 +</code>
 +
 +En pratique, cela donne :
 +
 +<code cpp main.cpp>
 +#include <iostream>
 + 
 +int main() {
 +    int x { 123 };
 +    std::cout << x << std::endl;
 +    x = 456;
 +    std::cout << x << std::endl;
 +}
 +</code>
 +
 +affiche :
 +
 +<code>
 +123
 +456
 +</code>
 +
 +<note>**Confusion possible**
 +
 +Attention à ne pas confondre l'opérateur d'affectation pour modifier une variable ''='' avec l'opérateur de comparaison d'égalité ''==''.
 +
 +De plus, dans les syntaxes alternatives, il est possible d'écrire le code suivant pour créer une variable.
 +
 +<code cpp>
 +int x = 123; // initialisation
 +    x = 456; // affectation
 +</code>
 +
 +Notez la différence : une initialisation contient le type puis l'identifiant d'une variable, une affectation contient uniquement l'identifiant.
 +
 +Pour éviter la confusion, il est recommandé d'utiliser la syntaxe avec des accolades pour l'initialisation et celle avec ''='' pour l'affectation.
 +</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 modifiez effectivement pas cette variable et de réaliser certaines optimisations.
 +
 +<code cpp main.cpp>
 +#include <iostream>
 + 
 +int main() {
 +    const int x { 123 };
 +    x = 456; // erreur
 +}
 +</code>
 +
 +affiche :
 +
 +<code>
 +main.cpp: In function 'int main()':
 +main.cpp:5:7: error: assignment of read-only variable 'x'
 +     x = 456; // erreur
 +       ^
 +</code>
 +
 +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.
 +
 +<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 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 cpp>
 +const int i { 123 };
 +int const j { 456 };
 +</code>
 +
 +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>
 +
  
 ===== Le type d'une variable ===== ===== Le type d'une variable =====
Ligne 130: Ligne 301:
   * ''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) ;
-  * ''string'' correspond aux chaînes de caractères ; +  * ''std::string'' correspond aux chaînes de caractères ; 
   * ''char'' correspond à un caractère ;   * ''char'' correspond à un caractère ;
   * ''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é (qui accepte des valeurs négatives et positives) et non-signé (qui accepte uniquement des valeurs positives).
 +
 +<code cpp>
 +const int i { 123 };            // signed par défaut
 +const signed int j { 123 };     // signed explicite
 +const unsigned int k { 123 };   // unsigned
 +const unsigned int l { -123 };  // erreur, littérale signed dans une variable unsigned
 +</code>
  
 Pour rappel, voici comment s'écrivent les littérales correspondant à chaque type : Pour rappel, voici comment s'écrivent les littérales correspondant à chaque type :
Ligne 138: Ligne 318:
   * pour un ''int'' : par exemple ''123'' ou ''456'' ;   * pour un ''int'' : par exemple ''123'' ou ''456'' ;
   * pour un ''double'' : par exemple ''123.456'' ou ''123.456e789'' ;   * pour un ''double'' : par exemple ''123.456'' ou ''123.456e789'' ;
-  * pour un ''string'' : par exemple ''"hello, world!"'' ou ''"bonjour!"'' ;+  * pour un ''std::string'' : par exemple ''"hello, world!"'' ou ''"bonjour!"'' ;
   * pour un ''char'' : par exemple 'a' ou 'z' ;   * pour un ''char'' : par exemple 'a' ou 'z' ;
   * pour un ''bool'' : uniquement ''true'' ou ''false''.   * pour un ''bool'' : uniquement ''true'' ou ''false''.
Ligne 187: 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 210: Ligne 390:
 </code> </code>
  
-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). +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.
- +
-Avoir un contrôle sur les types par le compilateur permet de garantir leur utilisation correcte (//type safety//). Ce typage fort est une des forces du C++ et il est intéressant de permettre au compilateur de faire un maximum de vérification. On reviendra sur le typage fort juste après.+
  
 **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 faire n'importe quoi dans son coin.+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.
  
 +**Typage fort**
  
- +Avoir un contrôle sur les types par le compilateur permet de garantir leur utilisation correcte (//type safety//). Plus la prise en compte des types est importante, plus vous aurez de garantie sur le code. Ce typage fort est une des forces du C++ et il est intéressant de permettre au compilateur de faire un maximum de vérifications.
-==== Typage fort ====+
  
 Dans tous les cas, il est important d'accorder une attention particulière aux types des variables et des données dans vos codes C++. Dans tous les cas, il est important d'accorder une attention particulière aux types des variables et des données dans vos codes C++.
- 
- 
-<note>**Importance du typage fort** 
- 
-Vous avez vu dans les chapitres précédents que le C++ accorde une importance particulière aux types des données. Une même valeur, par exemple 3, pourra signifier différentes choses selon le type : ''3'' pour un nombre entier, ''3.0'' pour une nombre réel, ''"3"'' pour une chaîne de caractères, '3' pour un caractère. 
- 
-Ce principe de typage fort s'applique également pour les variables : une variable est créée avec un type défini et ne pourra pas changer de type. Si vous créez une variable de type entier par exemple (i.e. pouvant contenir des nombres entiers), vous ne pourrez pas mettre un autre type dedans. 
-</note> 
  
 ===== L'identifiant ===== ===== L'identifiant =====
Ligne 241: Ligne 411:
  
 <code cpp> <code cpp>
-int const x { 123 }; // x correspond à un entier +#include <iostream> 
-int const x { 456 }; // erreur : l'identifiant x est déjà utilisé+ 
 +int main() { 
 +    int const x { 123 }; // x correspond à un entier 
 +    int const x { 456 }; // erreur : l'identifiant x est déjà utilisé 
 +}
 </code> </code>
 +
 +affiche :
 +
 +<code>
 +main.cpp: In function 'int main()':
 +main.cpp:6:15: error: redeclaration of 'const int x'
 +     int const x { 456 }; // erreur : l'identifiant x est déjà utilisé
 +               ^
 +main.cpp:5:15: note: 'const int x' previously declared here
 +     int const x { 123 }; // x correspond à un entier
 +               ^
 +</code>               
  
 Pour écrire un identifiant, vous pouvez utiliser les caractères alphanumériques minuscules et majuscules (''a'' à ''z'', ''A'' à ''Z'' et ''0'' à ''9'') et le tiret bas ''_'' (//underscore//, correspond à la touche 8 sur un clavier français). De plus, un identifiant doit obligatoirement commencer par une lettre. Pour écrire un identifiant, vous pouvez utiliser les caractères alphanumériques minuscules et majuscules (''a'' à ''z'', ''A'' à ''Z'' et ''0'' à ''9'') et le tiret bas ''_'' (//underscore//, correspond à la touche 8 sur un clavier français). De plus, un identifiant doit obligatoirement commencer par une lettre.
Ligne 256: Ligne 442:
   * ''UnEvArIaBlE''.   * ''UnEvArIaBlE''.
  
-En revanche, les identifiants suivants ne sont pas valides :+En revanche, les identifiants suivants ne sont pas valides ou sont déconseillés :
  
   * ''_une_variable'' : commence par un tiret bas ;   * ''_une_variable'' : commence par un tiret bas ;
   * ''123variable'' : commence par un chiffre ;   * ''123variable'' : commence par un chiffre ;
   * ''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.</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 :
  
   * ''jjfndsfkjgukzv'' : ne veut rien dire, n'apporte pas d'information sur le rôle de cette variable ;   * ''jjfndsfkjgukzv'' : ne veut rien dire, n'apporte pas d'information sur le rôle de cette variable ;
-  * ''une_variable'' : trop générique ; +  * ''une_variable'' : trop générique, ne dit pas quel est le rôle de cette variable 
-  * ''variable1'', ''variable2'', etc. : idem +  * ''variable1'', ''variable2'', etc. : trop générique aussi 
-  * ''UnEvArIaBlE'' : peu lisible ;+  * ''UnEvArIaBlE'' : le mélange de minuscule et majuscules rend ce nom peu lisible ;
   * ''une_variable_qui_contient_le_resultat_du_premier_calcul'' : trop long.   * ''une_variable_qui_contient_le_resultat_du_premier_calcul'' : trop long.
  
-Bonne pratique de codage : règles que vous vous imposez ainsi qu'aux développeurs qui participent à un projet, pour faciliter la lecture du code par tous. Le but est d'avoir des noms homogènes, simples et informatifs.+Dans les projets réalisés en équipe, une bonne pratique est de définir des règles ("bonnes pratiques de codage") qui s'imposent à tous les développeurs du projet, pour faciliter la lecture du code. Le but est d'avoir des noms homogènes, simples et informatifs.
  
-Il existe déjà des "règles de codagetoutes faites, vous pouvez utiliser vos propres règles. Les conventions de nommage les plus connues ''une_variable'' (STL, Boost)''uneVariable'' (Qt)+Il existe déjà des règles de bonnes pratiques de codage toutes faites, mais vous pouvez aussi utiliser vos propres règles. Les conventions de nommage les plus connues écrivent les noms en minuscules séparées par un tiret bas (''une_variable'', par exemple dans la bibliothèque standard ou Boost) ou en écrivant les noms avec des majuscule au début de chaque mot et sans séparateur (''uneVariable'', par exemple dans la bibliothèque Qt).
  
-<note info>Pour le moment3 sources de règles pour écrire du code :+Le nom des variables participe à la qualité d'un code. Plus le nom d'une variable est informatif sur le rôle de cette variablemoins vous aurez de risque de mal utiliser cette variable.
  
-  * le langage C++, imposé par le compilateur ; 
-  * les règles de conception, imposées par la qualité logicielle ; 
-  * les règles de codage, que vous vous imposez. 
-</note> 
  
 ===== La valeur ===== ===== La valeur =====
  
-Une variable contient obligatoirement une valeur. Il est possible de définir une variable sans l'initialiser, mais cette variable pourra alors contenir une valeur aléatoire. Cependant, vous imaginez bien qu'un programme ne va pas forcément fonctionner correctement si certaines variables sont initialisées avec des valeurs aléatoires. Nous n'allons pas voir toutes les syntaxes possibles pour initialiser une variable, mais uniquement celles qui sont recommandées.+Une variable contient obligatoirement une valeur. Il est possible de définir une variable sans l'initialiser, mais cette variable pourra alors contenir une valeur aléatoire. Cependant, vous imaginez bien qu'un programme ne va pas forcément fonctionner correctement si certaines variables sont initialisées avec des valeurs non déterminées
  
 Une variable peut être initialisée avec une valeur par défaut (//value initialization//), avec une littérale (//direct initialization//) ou avec une expression (//copy initialization//). Une variable peut être initialisée avec une valeur par défaut (//value initialization//), avec une littérale (//direct initialization//) ou avec une expression (//copy initialization//).
Ligne 290: Ligne 474:
   * initialisation avec une littérale : ''Type Identifiant { Valeur };'' ;   * initialisation avec une littérale : ''Type Identifiant { Valeur };'' ;
   * initialisation avec une expression : ''Type Identifiant { Expression };''.   * initialisation avec une expression : ''Type Identifiant { Expression };''.
- 
-Le signe ''='' utilisé pour attribuer une valeur à une variable s'appelle l'opérateur d'affectation. 
  
 Plus concrètement, avec du code : Plus concrètement, avec du code :
Ligne 301: Ligne 483:
 int main() { int main() {
     // Initialisation par défaut     // Initialisation par défaut
-    int const i_default {}; +    const int         i_default {}; 
-    double const d_default {}; +    const double      d_default {}; 
-    std::string const s_default {}; +    const std::string s_default {}; 
-    char const c_default {}; +    const char        c_default {}; 
-    bool const b_default {};+    const bool        b_default {};
          
     // Initialisation avec une valeur     // Initialisation avec une valeur
-    int const i_value { 123 }; +    const int         i_default { 123 }; 
-    double const d_value { 123.456 }; +    const double      d_default { 123.456 }; 
-    std::string const s_value { "hello, world!" }; +    const std::string s_default { "hello, world!" }; 
-    char const c_value { 'a' }; +    const char        c_default { 'a' }; 
-    bool const b_value { true }; +    const bool        b_default { true }; 
-    +        
     // Initialisation avec une expression     // Initialisation avec une expression
-    int const i_expression { 123 + 456 }; +    const int         i_default { 123 + 456}; 
-    double const d_expression { 12.34 + 56.78 }; +    const double      d_default { 12.34 + 56.78 }; 
-    std::string const s_expression { std::string{ "hello, " } + "world!" }; +    const std::string s_default { std::string{ "hello, " } + "world!" }; 
-    bool const b_expression { 123 > 456 };+    const char        c_default { 'a' }; 
 +    const bool        b_default { 123 > 456};
 } }
 </code> </code>
  
-Comme vous avez vu dans les codes précédents, il est possible d'afficher la valeur d'une variable directement avec ''cout''. Celui-ci est capable de connaître le type de la variable et d'afficher correctement la valeur, comme si vous aviez écrit une littérale directement avec ''cout''. Vous pouvez également utiliser directement une variable dans un calcul.+Note : l'expression avec ''std::string'' est un peu plus complexe, du fait de certaines règles de manipulation des chaînes de caractères. Vous verrez cela plus en détail dans le chapitre sur les chaînes.
  
-<code cpp> 
-int const x { 123 }; 
-std::cout << "La valeur de x est : " << x << std::endl; 
-int const y { x * 45 }; 
-</code> 
-===== Portée et durée de vie ===== 
  
 +===== Portée d'une variable =====
  
-Une variable existe à partir du moment où vous la créez, pas avantVous ne pouvez pas utiliser une variable dans une ligne de code et la définir ensuite.+Une variable existe à partir du moment où elle est déclarée et jusqu'à la fin du bloc contenant sa déclarationCela s'appelle la portée de la variable. Utiliser une variable avant de l'avoir définie produit donc une erreur.
  
-<code cpp> +<code cpp main.cpp> 
-cout << << endl;  // erreur : la variable x est inconnue à cette ligne, elle est +#include <iostream> 
-                    // définie uniquement à partir de la ligne suivante + 
-                     +int main() { 
-int { 123 };      // création de i+    std::cout << << std::endl; 
 +    const int { 123 }; 
 +}
 </code> </code>
  
-===== De nouveaux opérateurs arithmétiques ===== +affiche :
- +
-Modifier une variable non ''const'' : utilisation de l'opérateur d'affectation ''=''. +
- +
-Combinaison de l'opérateur d'affectation et d'opérateurs arithmétiques :+
  
 <code> <code>
-a = a + b;  +main.cpp: In function 'int main()': 
-a += b; +main.cpp:4:18: error: 'x' was not declared in this scope 
- +     std::cout <;< x << std::endl
-a = a * b; +                  ^
-a *= b+
- +
-etc.+
 </code> </code>
  
-===== Constantes =====+Ce qui signifie "x n'est pas déclarée dans cette portée".
  
-Lorsque vous ne modifiez pas une variable après l'avoir initialiséeon peut considérer que cette variable est constante. Vous pouvez indiquer cette information au compilateur en ajoutant le mot-clé ''const'' ("constant") comme modificateur de typeAinsi :+Il est également possible d'ajouter des blocs supplémentairespour limiter la portée des variables.
  
-  * ''int'' : représente un type entier ; +<;code cpp main.cpp> 
-  * ''int const'' (ou ''const int'') : représente un type entier constant.+#include <iostream>
  
-Indiquer cette information permet au compilateur de faire certaines optimisations (ce que vous ne verrez pas forcément sur un petit programme, mais cela peut avoir un impact sur un programme complexeet surtout cela permet au compilateur de vérifier que vous ne modifiez pas cette variable par la suite. +int main() { 
- +    const int x { 123 };              // début de portée de x    // 
-<code cpp> +    {                                 //                         // 
-int x { 123 }; +        const int y { 456 }     //                         // début de portée de y 
-456; // ok, x n'est pas constant +        std::cout << x << std::endl;  // ok, x existe            // 
- +        std::cout << << std::endl;  //                         // ok, y existe 
-int const { 123 }; +                                    //                         // fin de portée de y 
-= 456; // erreur, y est constant+    std::cout <;< x << std::endl;      // ok, x existe            // 
 +    // std::cout << <;< std::endl;   //                         // erreur, y est hors de portée 
 +}                                     // fin de portée de x      //
 </code> </code>
  
-L'utilisation de ''const'' apporte une garantie plus forte sur votre codevous devez systématiquement réfléchir aux rôles de vos variables et si elles doivent être modifiées durant l'exécution de votre programme ou nonEt donc utiliser le mot-clé ''const'' aussi souvent que nécessaire.+Note : dans la partie sur les identifiantsil est dit qu'un identifiant devait être uniqueEn fait, la règle est plus précisément "il ne faut pas avoir deux identifiants identiques dans la même portée". Il est donc possible d'avoir plusieurs variables portant le même identifiant, si leur portée est différente.
  
-<note info>**Notion de contrat**+<code cpp main.cpp> 
 +#include <iostream>
  
-Le typage des variables et l'utilisation de ''const'' est une forme de contrat que vous passez avec le compilateur. Vous lui dites que vous allez respecter un certain nombre de contraintes (les valeurs seront d'un type défini, les variables ne seront pas modifiées), celui-ci pourra alors vérifier que vous respectez ces contraintes et fera éventuellement des optimisations. +int main() { 
- +    { 
-La programmation par contrat est une approche qui permet d'améliorer la qualité de votre code et qui est plus complet que ce qui est présenté ici. Vous verrez dans la suite du cours comment utiliser efficacement la programmation par contrat en C++, en particulier pour créer vos propres types.</note&gt+        const int x { 123 }; 
- +        std::cout <&lt; x << std::endl
-===== Variable temporaire et non temporaire ===== +    } 
- +    { 
-En pratique, lorsque l'on écrit : +        const int x { 456 }; 
- +        std::cout <&lt; x <;< std::endl; 
-<code cpp&gt; +    } 
-int = y + z;+}
 </code> </code>
  
-Que se passe-t-il en réalité ?+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.
  
-  - Chargement de y et z depuis la mémoire dans le processeur. +<note>**Durée de vie (lifetime)**
-  - Calcul et résultat dans le processeur. +
-  - Retour du résultat du processeur vers la mémoire.+
  
-Le résultat du processeur est une variable non nommée (typevaleur) temporaire (pas en mémoire)Cette variable temporaire s'appelle une //rvalue// (pour //right value//, du fait qu'une rvalue ne peut être qu'à droite du signe d'affectation).+Une autre notion importante concernant les objetsc'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éeEssayez 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//).
  
-Au contrairexyet z sont des variables nommées non temporaires. Ces variables s'appellent des //lvalue// (pour //left value//du fait qu'une lvalue qui peut être à gauche).+Il existe plusieurs types de variables (dynamiquestatiqueetc)mais pour le momentvous 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
  
-Bien faire attention à la différence : c'est l'expression (y + z) qui est une rvalue, y et z en eux-mêmes sont des lvalue.+**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.**
  
-&lt;note warning&gt;Note sur bool +On parle parfois de &quot;variable automatique&quot;, du fait que l'objet est détruit automatiquementMais cette appellation n'est pratiquement plus utilisée, on parle simplement de "variable locale".
- +
-Certains types sont convertibles automatiquement en booléenpour pouvoir tester s'ils sont valides ou nonC'est le cas par exemple des littérales chaînes de caractères. Il est possible d'écrire le code suivant sans que cela ne produise d'erreur : +
- +
-<code cpp> +
-bool b { "hello, world}; +
-</code> +
-</note>+
  
-===== Lecture complémentaire =====+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>
  
-Sur les anciennes syntaxes pour initialiser : [[https://marcmutz.wordpress.com/tag/explicit/|A case against direct initialisation]] 
  
-^ [[ratio|Chapitre précédent]] ^ [[programmez_avec_le_langage_c|Sommaire principal]] ^ [[inference_de_type|Chapitre suivant]] ^ 
  
-{{tag> Cours C++}}+^ [[ratio|Chapitre précédent]] ^ [[programmez_avec_le_langage_c|Sommaire principal]] ^ [[enum_class|Chapitre suivant]] ^
rvalue_et_lvalue.1443804795.txt.gz · Dernière modification: 2015/10/02 18:53 par gbdivers