Menu

const et constantes en C++ : const, constexpr et consteval

Comment déclarer des valeurs en lecture seule en C++ avec const, la différence entre const et constexpr, les pointeurs const par rapport aux pointeurs vers const, et les fonctions membres const.

Cette page contient des éditeurs exécutables - modifiez, exécutez et voyez la sortie instantanément.

Pourquoi les constantes existent

Une constante est une valeur que vous promettez de ne jamais changer après l'avoir définie. Marquer quelque chose const remplit deux rôles à la fois : cela documente votre intention auprès de quiconque lit le code, et cela permet au compilateur d'imposer cette intention — toute ligne qui tente de modifier la valeur devient une erreur de compilation plutôt qu'un bug silencieux à l'exécution.

Là où le mot-clé auto laisse le compilateur déduire le type d'une variable, const restreint ce que vous pouvez faire avec cette variable. Les deux se combinent librement : const auto limit = 100; est un int en lecture seule.

Déclarer une valeur const

Placez const avant le type. Une variable const doit être initialisée sur la même ligne, car il n'existe aucun moment ultérieur où vous serez autorisé à lui affecter une valeur.

Décommentez l'affectation et le programme ne compilera pas — le compilateur signale « assignment of read-only variable ». C'est précisément le but : l'erreur est détectée avant même que le programme ne s'exécute.

Une habitude courante de débutant héritée du C est #define MAX_USERS 100. Évitez-la. Une macro est une substitution de texte aveugle, sans type et sans respect de la portée ; elle ne peut donc pas être inspectée dans un débogueur et produit des messages d'erreur déroutants. Une variable const (ou constexpr) est vérifiée par le système de types et a une portée comme n'importe quelle autre.

const vs constexpr

Les deux mots-clés vous donnent une valeur qui ne peut pas changer, mais ils répondent à des questions différentes. const dit « ceci ne change jamais après avoir été défini ». constexpr dit, plus fort encore, « ceci peut être calculé à la compilation » — et tout ce qui est constexpr est automatiquement const aussi.

La règle empirique : optez pour constexpr chaque fois que la valeur est un littéral fixe ou un calcul que le compilateur peut faire (tailles de tableaux, longueurs de tampons, étiquettes de switch, arguments de templates). Utilisez const simple lorsque la valeur est décidée à l'exécution mais ne doit pas changer ensuite — comme une copie const d'un argument de fonction.

Depuis C++20, il existe aussi consteval, utilisé sur les fonctions qui doivent s'exécuter à la compilation :

consteval int square(int x) { return x * x; }
constexpr int area = square(8); // calculé pendant la compilation

Une fonction constexpr peut s'exécuter à la compilation ; une fonction consteval doit toujours le faire, sinon c'est une erreur.

Pointeurs et const : lisez de droite à gauche

C'est ici que const piège les gens, car le mot-clé peut se placer de chaque côté du * et les deux significations sont opposées. L'astuce consiste à lire la déclaration de droite à gauche.

Lisez int* const p2 de droite à gauche : « p2 est un pointeur const vers int ». Lisez const int* p1 ainsi : « p1 est un pointeur vers const int ». Trompez-vous là-dessus et vous perdrez un temps réel, dérouté par une erreur qui dit que vous ne pouvez pas modifier quelque chose que vous pensiez mutable.

Un piège pratique : ne prenez jamais l'adresse d'un const pour ensuite retirer le const par un cast afin de modifier l'objet sous-jacent. Faire cela relève du comportement indéfini si l'objet d'origine était réellement const, et le compilateur est libre de supposer que la valeur ne change jamais — votre « écriture » peut tout simplement être ignorée.

Les références const comme paramètres de fonction

L'usage quotidien le plus courant de const consiste à passer de gros objets par référence sans les copier. Un paramètre const& évite la copie et promet que la fonction ne modifiera pas l'argument de l'appelant.

Le passage par const& est le choix par défaut pour tout paramètre plus grand que quelques octets (chaînes, vecteurs, vos propres classes). Notez qu'il permet aussi à la fonction d'accepter un temporaire comme "Grace" — une référence non const simple ne peut pas se lier à un temporaire, donc retirer le const ici rejetterait ce second appel.

Fonctions membres const

Lorsque vous écrivez une classe, marquez d'un const final toute méthode qui ne modifie pas l'objet. C'est ce qui rend la méthode appelable sur des instances const et des paramètres const& — sans cela, vous ne pouvez pas lire votre propre objet à travers une poignée const.

La discipline qui consiste à marquer const les méthodes en lecture seule s'appelle la const correctness. Faites-le correctement dès le début — une méthode qui aurait dû être const est facile à ajouter, mais réintroduire const dans une grande base de code par la suite est pénible, car chaque appelant passant par une référence const en dépend.

Suite : les opérateurs

Maintenant que vos valeurs peuvent être verrouillées avec const, l'étape suivante consiste à en faire quelque chose. La page sur les opérateurs couvre les opérateurs arithmétiques, de comparaison, logiques et d'affectation — y compris les pièges autour de la division entière, de la priorité des opérateurs et de la façon dont const interagit avec les opérateurs d'affectation que vous n'avez pas le droit d'utiliser.

Questions fréquentes

Quelle est la différence entre const et constexpr en C++ ?

const signifie que la valeur ne peut pas changer après l'initialisation, mais elle peut être calculée à l'exécution. constexpr est plus fort : il garantit que la valeur peut être calculée à la compilation, de sorte qu'elle peut être utilisée là où une constante de compilation est requise (tailles de tableaux, arguments de templates, étiquettes de switch). Tout objet constexpr est aussi const, mais tout objet const n'est pas constexpr.

Comment déclarer une constante en C++ ?

Placez const avant le type et donnez-lui une valeur : const int maxUsers = 100;. Une variable const doit être initialisée au moment de sa déclaration, car vous ne pourrez jamais lui affecter une valeur par la suite. Pour les constantes de compilation, préférez constexpr int maxUsers = 100;. Évitez l'ancienne macro #define à la C : elle n'a pas de type et ignore la portée.

Que signifie un pointeur const en C++ ?

Cela dépend de l'emplacement de const. const int* p est un pointeur vers const : vous pouvez faire pointer p ailleurs, mais vous ne pouvez pas modifier *p. int* const p est un pointeur const : vous pouvez modifier *p, mais vous ne pouvez pas faire pointer p ailleurs. Lisez la déclaration de droite à gauche : int* const signifie "pointeur const vers int".

Coddy programming languages illustration

Apprendre à coder avec Coddy

COMMENCER