Main menu:

Site search

Categories

avril 2008
L M M J V S D
 123456
78910111213
14151617181920
21222324252627
282930  

Archive

C++ – Constantes

Lorsque l’on veut préciser que la valeur d’un objet ne varie pas, on peut le faire précéder du mot-clé const.

const int i = 10;

L’objet étant constant, il doit être initialisé au moment de sa déclaration.

const int i;

Erreur i n’est pas initialisé.

const int i = f();

Ok même si la valeur d’initialisation n’est pas connue au moment de la compilation.

void g(const int i)
{
  // garantit que i ne sera pas modifié
  // par la fonction
}

Dans le cas où l’objet est initialisé avec une valeur connue au moment de la compilation, le compilateur n’a pas besoin d’allouer de la mémoire pour cet objet.

const int i = 10;

Le compilateur connait la valeur de i et remplace directement dans le code à chaque fois que i est utilisé, i par sa valeur 10. Aucune mémoire n’est allouée à i. Aucune adresse n’existe contenant i.
Examinons le code assembleur produit par g++ pour le petit programme suivant en le compilant avec l’option -S (g++ -S test.cpp).

int main()
{
  const int i = 10;
  int j = i;
  return 0;
}

Le code assembleur généré pour 1 et 2 est le suivant:

movl  $10, -12(%ebp)      // const int i = 10;
movl  $10, -8(%ebp)       // int j = i

Le compilateur attribue à j la valeur 10 directement sans utiliser i.

Comparons avec ce code-ci:

int main()
{
  int i = 10;
  int j = i;
  return 0;
}

Le code assembleur généré par g++ est celui-ci:

movl  $10, -12(%ebp)    // int i = 10;
movl  -12(%ebp), %eax   // on charge eax avec la valeur de i
movl  %eax, -8(%ebp)    // on copie eax dans j

On remarque que ce code est moins efficace que la version avec i constant puisque le compilateur doit d’abord chargé un registre du processeur (eax) avec la valeur de i et ensuite copier ce registre dans j. C’est donc plus lent et moins efficace que dans le cas de i constant.

Donc, déclarez vos objets constants chaque fois que possible. Vous gagnerez en vitesse, en efficacité et votre code sera plus sûr, le compilateur garantissant que vos objets ne pourront en aucun cas être modifiés (const correctness). Une constante non-déclarée const et modifiée dans le code est toujours un bug difficile à déceler dans un code source un peu important.

Trois remarques supplémentaires:
Premièrement, les objets constants ont une liaison interne (internal linkage) sauf si ils sont déclarés extern. Cela veut dire que vous pouvez déclarer vos objets constants dans les fichiers d’entête sans risque que le compilateur vous donne une erreur du type « déclaration multiple », ces objets étant locaux à chaque fichier.

Deuxièmement, le mot-clef const modifie l’objet qui est à sa gauche. S’il n’y a rien à sa gauche alors il modifie l’objet à sa droite. Autement dit:

const string& s

et

string const & s

sont identiques. Dans le premier cas, il n’y a rien à la gauche du const et donc il modifie string et s est donc une référence vers un string constant. Dans le deuxième cas, const modifie ce qui est à sa gauche c’est à dire string et donc s est une référence vers un string constant. C’est bien la même signification dans les deux cas.

Troisièmement, examinons les fonctions suivantes:

void f(string s);
void g(string& s);
void h(const string& s);

string str;
f(str);
g(str);
h(str);

Dans le cas de la fonction f(str), str est passé par valeur et s est une nouvelle instance de str. Toute modification de s dans la fonction est perdue.
Dans g(str), s est le même objet que str et donc toute modification de s entraine la modification de str.
Dans h(str), s est aussi le même objet que str mais sa modification dans la fonction n’est pas permise parce que déclaré const.