Le qualificatif const avec les paramètres pointeurs
Pour comprendre cette notion, prenons une fonction simple qui renvoie le plus petit élément d'un tableau.
Exemple 1 : Version sans const
double plusPetite(double Tab[], size_t cpt)
{
if (!cpt) return NULL; // tableau vide retourner NULL
size_t index_min {};
for (size_t i {1}; i < cpt; ++i) {
if (Tab[index_min] > Tab[i])
index_min = i;
}
return Tab[index_min];
}La fonction plusPetite() doit seulement accéder aux valeurs des éléments du tableau ; elle n'a pas besoin de les modifier. Il serait bon de s'assurer que le code de la fonction ne modifie pas accidentellement les éléments du tableau.
Exemple 2 : Version avec const
double plusPetite(const double Tab[], size_t cpt)
{
if (!cpt) return NULL; // tableau vide retourner NULL
size_t index_min {};
for (size_t i {1}; i < cpt; ++i) {
if (Tab[index_min] > Tab[i])
index_min = i;
}
return Tab[index_min];
}En ajoutant ce qualificatif const, vous demandez au compilateur de vérifier que les éléments du tableau ne sont pas modifiés dans le corps de la fonction.
Si vous tentez accidentellement de modifier un élément, le compilateur générera une erreur.
Les deux conséquences de const sur un paramètre pointeur
Vérification par le compilateur
Le compilateur vérifie le code dans le corps de la fonction pour s'assurer que vous n'essayez pas de changer la valeur pointée.
double plusPetite(const double Tab[], size_t cpt)
{
Tab[0] = 10.0; // ERREUR DE COMPILATION !
// ...
}Appel avec des constantes
La fonction peut être appelée avec un argument qui pointe vers une constante.
const double donnees[] = {5.5, 2.3, 9.1, 1.8};
double min = plusPetite(donnees, 4); // OK
double valeurs[] = {5.5, 2.3, 9.1, 1.8};
double min2 = plusPetite(valeurs, 4); // OK aussiParamètres de type de base (passés par valeur)
Dans notre dernière définition de plusPetite(), nous n'avons pas déclaré le paramètre cpt de la fonction comme const également.
Si un paramètre d'un type de base tel que int ou size_t est passé par valeur, il n'a pas besoin d'être déclaré const, du moins pas pour la même raison.
Le mécanisme de passage par valeur fait une copie de l'argument lorsque la fonction est appelée. Vous êtes déjà protégé contre la modification de la valeur originale à l'intérieur de la fonction.
void fonction(int param) {
param = 42; // Modifie la COPIE, pas la variable originale
}
int main() {
int x = 10;
fonction(x); // x reste 10 après l'appel
}Peut-on déclarer cpt comme const ?
Cette directive générale s'applique à toutes les variables, y compris celles déclarées dans la liste des paramètres. Pour cette raison, et pour cette raison seulement, vous pouvez toujours envisager de déclarer cpt comme const.
double plusPetite(const double Tab[], const size_t cpt)
{
// ++cpt; // ERREUR : cpt est const
// ...
}Avantage : Vous évitez d'écrire accidentellement ++cpt quelque part dans le corps de la fonction, ce qui pourrait avoir des résultats désastreux.
double plusPetite(const double Tab[], size_t cpt)
{
++cpt; // COMPILE (mais modifie la copie)
// ...
}Remarque : Même sans const, la valeur originale de l'appelant n'est jamais modifiée (seule la copie l'est).
Si vous déclarez cpt comme const, vous déclarez alors une copie locale en tant que constante. Il n'est en aucun cas nécessaire d'ajouter const pour empêcher la modification de la valeur originale.
La protection de la valeur originale est déjà assurée par le mécanisme de passage par valeur.
Récapitulatif : const sur les paramètres
| Type de paramètre | Avec const | Sans const | Utilité |
|---|---|---|---|
| Pointeur (tableau) | Éléments non modifiables | Éléments modifiables | Protège les données pointées |
| Type de base (valeur) | Copie locale constante | Copie locale modifiable | Protège la copie (pas l'original) |
Exemple complet avec différents usages
#include <iostream>
// Version recommandée : tableau const, paramètre size_t normal
double minTableau(const double tab[], size_t taille)
{
if (taille == 0) return 0;
double min = tab[0];
for (size_t i = 1; i < taille; ++i) {
if (tab[i] < min)
min = tab[i];
}
return min;
}
// Version avec const partout (prévention d'erreurs locales)
double minTableauStrict(const double tab[], const size_t taille)
{
if (taille == 0) return 0;
double min = tab[0];
for (size_t i = 1; i < taille; ++i) {
if (tab[i] < min)
min = tab[i];
// ++i; // ERREUR si décommenté
}
return min;
}
int main()
{
const double notes[] = {15.5, 12.0, 18.5, 10.5};
double valeurs[] = {5.5, 2.3, 9.1, 1.8};
// Les deux appels fonctionnent avec les deux versions
std::cout << minTableau(notes, 4) << std::endl;
std::cout << minTableau(valeurs, 4) << std::endl;
std::cout << minTableauStrict(notes, 4) << std::endl;
std::cout << minTableauStrict(valeurs, 4) << std::endl;
return 0;
}- Utilisez const sur un paramètre pointeur pour garantir que la fonction ne modifie pas les données pointées.
- Le compilateur vérifie que le code respecte cette garantie.
- Une fonction avec paramètre const peut être appelée avec des arguments constants ou non constants.
- Pour les paramètres passés par valeur (types de base), const n'est pas nécessaire pour protéger l'original (une copie est déjà faite).
- Ajouter const sur un paramètre par valeur peut éviter des modifications accidentelles de la copie locale.
- La bonne pratique : toujours mettre const sur les paramètres pointeurs/références qui ne doivent pas être modifiés.
Discussion (0)
Soyez le premier à laisser un commentaire !
Laisser un commentaire
Votre commentaire sera visible après modération.