Déclarer un paramètre const en C++

22 Mar 2022 22 Mar 2022 2731 vues ESSADDOUKI Mostafa 6 min de lecture
Introduction et syntaxe de base
1 Introduction au langage C++ 2 Entrée-sortie en C++ - cin et cout 3 Inférence de type avec le mot-clé auto en C++ 4 Classe std::string et les chaînes de caractères en C++ 5 Les structures conditionnelles (if et switch) en C++ (C++17 et C++20) 6 Les boucles en C++ (C++17 et C++20) 7 La gestion des fichiers en C++
Pointeurs et fonctions
8 Introduction aux pointeurs en C++ - Déclaration et interêts 9 Les références en C++ - déclaration et interêts 10 Les tableaux en C++ - Déclaration et interêts 11 Introduction aux fonctions en C++ 12 Passer des arguments à une fonction en C++ 13 Déclarer un paramètre const en C++ 14 Les fonctions Lambda en C++ 15 Fonctions utiles (Mathématiques et caractères) en C++
Programmation OO
16 Classes et objets en C++ 17 Spécificateurs d'accès en C++ 18 Constructeurs et destructeur d'une classe en C++ 19 Fonctions membres en C++ 20 Membres statiques d'une classe en C++ 21 Fonctions en ligne en C++ - inline 22 Fonctions et classes amies en C++ - friend 23 Surcharge des fonctions en C++ 24 Surcharge des opérateurs en C++ 25 Héritage en C++ 26 La gestion d'exceptions en C++ : déclaration, utilisation et personnalisation 27 fonctions et classes templates en C++ 28 Les nouveautés C++20 pour améliorer les templates en C++
Structures de données
29 Introduction aux structures de données 30 Les structures en C++ et la différence avec les structures en C 31 Les listes chaînées en C++ 32 Les piles en C++ 33 File d'attente en C++ 34 Arbre binaire de recherche : définition et mise en oeuvre en C++
La bibliothèque standard (STL)
35 Introduction à la bibliothèque de Template Standard STL 36 Les itérateurs en C++ - définition, déclaration et exemples 37 La classe array en C++ (bibliothèque STL) <array> 38 La classe vector de la bibliothèque STL <vector> 39 La classe deque en C++ ( Bibliothèque STL) 40 La classe list en C++ (bibliothèque STL) <list> 41 La classe stack (Pile) en C++ (bibliothèque STL) <stack> 42 La classe queue (File d'attente) en C++ (bibliothèque STL) <queue> 43 La file d'attente prioritaire (classe priority_queue) - Bibliothèque STL 44 Les ensembles en C++ (Classe set <set> - Bibliothèque STL) 45 Les dictionnaires en C++ : Classe map (Bibliothèque STL) 46 Introduction aux algorithmes de la bibliothèque STL (programmation compétitive) 47 Tri et méthodes associées en C++ - Bibliothèque STL 48 Recherche dichotomique et méthodes associées en C++ - Bibliothèque STL 49 Appliquer un prédicat ou une fonction aux éléments d'une séquence en C++ - Bibliothèque STL 50 Recherche dans une séquence et méthodes associées en C++ - Bibliothèque STL

Le qualificatif const avec les paramètres pointeurs

Objectif

Pour comprendre cette notion, prenons une fonction simple qui renvoie le plus petit élément d'un tableau.

Exemple 1 : Version sans const

   
Fonction plusPetite - Version 1 C++
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];
}
Observation

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

   
Fonction plusPetite - Version 2 (avec const) C++
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];
}
Effet de const

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

Conséquence 1

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 !
    // ...
}
Conséquence 2

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 aussi

Paramètres de type de base (passés par valeur)

Particularité du passage 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.

Mécanisme de passage par valeur

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.

Avec 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.

Sans const
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).

Important à comprendre

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ètreAvec constSans constUtilité
Pointeur (tableau)Éléments non modifiablesÉléments modifiablesProtège les données pointées
Type de base (valeur)Copie locale constanteCopie locale modifiableProtège la copie (pas l'original)

Exemple complet avec différents usages

   
Exemple illustrant les différentes possibilités C++
#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;
}
Points clés à retenir
  • 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.