Vendez-moi sur la correction de const

133

Alors pourquoi exactement est-il toujours recommandé d'utiliser const aussi souvent que possible? Il me semble que l'utilisation de const peut être plus pénible qu'une aide en C ++. Mais là encore, j'arrive à ceci du point de vue de python: si vous ne voulez pas que quelque chose soit changé, ne le changez pas. Cela dit, voici quelques questions:

  1. Il semble que chaque fois que je marque quelque chose comme const, j'obtiens une erreur et je dois changer une autre fonction quelque part pour qu'elle soit également const. Ensuite, cela m'oblige à changer une autre fonction ailleurs. Est-ce quelque chose qui devient plus facile avec l'expérience?

  2. Les avantages de l'utilisation de const sont-ils vraiment suffisants pour compenser le problème? Si vous n'avez pas l'intention de changer un objet, pourquoi ne pas simplement écrire du code qui ne le change pas?

Je dois noter qu'à ce stade, je me concentre surtout sur les avantages de l'utilisation de const à des fins d'exactitude et de maintenabilité, bien qu'il soit également agréable d'avoir une idée des implications sur les performances.

Jason Baker
la source
1
Rétrospective de 8 ans, mais ... Que diriez-vous d'accélérer votre code 100x (vu ça en direct)?
lorro le
1
Vérifiez ma réponse ici (question connexe, je dirais la même réponse): stackoverflow.com/questions/42310477/... BTW: I do loveconst
Gines Hidalgo

Réponses:

158

Voici l'article définitif sur la "correction de const": https://isocpp.org/wiki/faq/const-correctness .

En un mot, utiliser const est une bonne pratique car ...

  1. Il vous protège contre les modifications accidentelles de variables qui ne sont pas destinées à être modifiées,
  2. Il vous protège contre les affectations accidentelles de variables, et
  3. Le compilateur peut l'optimiser. Par exemple, vous êtes protégé contre

    if( x = y ) // whoops, meant if( x == y )

En même temps, le compilateur peut générer un code plus efficace car il sait exactement quel sera l'état de la variable / fonction à tout moment. Si vous écrivez du code C ++ serré, c'est bien.

Vous avez raison en ce sens qu'il peut être difficile d'utiliser const-correctness de manière cohérente, mais le code final est plus concis et plus sûr à programmer. Lorsque vous faites beaucoup de développement C ++, les avantages de cela se manifestent rapidement.

Jordan Parmer
la source
J'ai toujours supposé que les valeurs const pouvaient être librement mises en cache et ainsi éviter de nombreux problèmes de concurrence ou améliorer la vitesse. Est-ce vrai?
Phil H du
3
Sûr. constLes variables peuvent améliorer la vitesse dans le sens où le compilateur peut générer un code plus optimal car il connaît l'intention et l'utilisation complètes de la variable. Allez-vous remarquer la différence? Eh bien, cela est discutable lors de votre candidature. En ce qui concerne la concurrence, les variables const sont en lecture seule, ce qui signifie qu'il n'y a pas besoin de verrous exclusifs sur ces variables puisque la valeur sera toujours la même.
Jordan Parmer
4
À partir de C ++ 11, la bibliothèque standard suppose également constqu'elle est sûre pour les threads et le traitement de votre propre code de cette manière facilite la recherche d'éventuels problèmes de multi-threading et constitue un moyen simple de fournir des garanties API à vos utilisateurs d'API.
pmr
3
Pour moi, l'une des plus grandes valeurs ajoutées de la correction de const est que vous savez simplement en regardant les prototypes de fonction lorsque les pointeurs référencent des données qui ne sont jamais mutées par la fonction (c'est-à-dire en entrée uniquement).
cp.engr
1
N'oubliez pas qu'il y a constness logique et physique . Tout objet agrégé contenu qui est marqué comme mutable peut changer, bien que le marquer comme tel implique qu'il n'a rien à voir avec la constance logique de l'objet conteneur.
Adrian
128

Voici un morceau de code avec une erreur courante contre laquelle la correction de const peut vous protéger:

void foo(const int DEFCON)
{
   if (DEFCON = 1)     //< FLAGGED AS COMPILER ERROR! WORLD SAVED!
   {
       fire_missiles();
   }
}
Doug T.
la source
19
Nous disons donc que const est nécessaire car un idiot a choisi "=" comme opérateur d'affectation dans C? ;-)
Steve Jessop
37
Bien sûr, la plupart des compilateurs modernes avertissent des affectations dans des conditions conditionnelles et nous
activons
7
Ne soyez pas trop dur sur cet exemple: c'est le même exemple évangélisé par certains développeurs pour nous convaincre d'utiliser if (0 == i) au lieu de if (i == 0). Enfin, le modèle de code de Doug peut être utilisé en dehors de l'instruction "if". Ce qui est important, c'est qu'il montre l'un des avantages de const de manière humoristique. + 1.
paercebal
2
Certains compilateurs (et lints) ont mis en garde à ce sujet depuis longtemps, et c'est beaucoup plus utile pour attraper cette faute de frappe que const: codepad.org/Nnf5JUXV .
7
@Roger, vous supposez que nous vivons dans un monde où les versions sont propres et sans avertissement. Mon expérience est que dans de nombreux codes, les avertissements se perdent dans le bruit. De plus, il y a beaucoup de code qui effectue des affectations dans l'expression if et beaucoup diront que c'est un style valide et «bon».
Doug T.
62

Il semble que chaque fois que je marque quelque chose comme const, j'obtiens une erreur et je dois changer une autre fonction quelque part pour qu'elle soit également const. Ensuite, cela m'oblige à changer une autre fonction ailleurs. Est-ce quelque chose qui devient plus facile avec l'expérience?

Par expérience, c'est un mythe total. Cela se produit lorsque non const-correct se trouve avec un code const-correct, bien sûr. Si vous concevez const-correct depuis le début, cela ne devrait JAMAIS être un problème. Si vous créez quelque chose de const, et que quelque chose d'autre ne se complète pas, le compilateur vous dit quelque chose d'extrêmement important et vous devriez prendre le temps de le réparer correctement .

Chris Mayer
la source
7
Cela m'a aidé à éviter tant de bogues où j'avais une fonction const sur le point d'appeler une fonction non-const parce que j'avais oublié qu'elle modifiait les données en dessous.
Mooing Duck
9
Très peu de gens commencent toujours avec des bases de code propres. La plupart du codage est une maintenance sur le code hérité, où le commentaire cité est assez précis. J'utilise const lors de l'écriture de nouvelles fonctions feuille, mais je me demande s'il vaut la peine de parcourir une demi-douzaine ou une douzaine de niveaux d'appel de code inconnu.
Warren Dew
3
C'est complètement faux dans mon expérience. Les types de points imbriqués créent le plus gros casse-tête pour ce genre de chose, où vous pouvez avoir plusieurs quantificateurs const dans un seul type.
Noldorin
4
"Si vous concevez const-correct depuis le début," combien de fois avez-vous réellement le luxe de forcer const-correctness dès le départ ?? La plupart d'entre nous doivent gérer quotidiennement de nombreuses API et bibliothèques lorsque ce n'est pas le cas et que vous ne pouvez pas y faire grand-chose. Je suis donc d'accord avec le sentiment des OP "Il semble que chaque fois que je marque quelque chose comme const, j'obtiens une erreur" ...
nyholku
@WarrenDew C'est un argument transitif; si les auteurs originaux avaient utilisé constcorrectement (c'est-à-dire "depuis le début") alors en effet il n'y aurait pas de problème, ce qui est exactement le point!
Courses de légèreté en orbite
31

Ce n'est pas pour vous lorsque vous écrivez le code initialement. C'est pour quelqu'un d'autre (ou vous quelques mois plus tard) qui regarde la déclaration de méthode à l'intérieur de la classe ou de l'interface pour voir ce qu'elle fait. Ne pas modifier un objet est une information importante à glaner.

Antonio Haley
la source
1
C'est seulement vrai. Const est également utilisé comme protection pour appliquer des variables internes via des interfaces, etc.
Jordan Parmer
C'est vrai, mais vous pouvez appliquer cela grâce à des pratiques de codage disciplinées et les états de l'affiche. Le véritable avantage vient du fait que cela se reflète dans l'API.
Antonio Haley
2
Exactement. Il est préférable d'avoir "const int Value = 5;" que d'avoir "int ConstValue = 5;". +1.
paercebal
6
Le bon moment pour mettre en place const-correctness est lorsque vous écrivez l'API initialement. Sinon, vous aurez des problèmes avec l'empoisonnement des constants lorsque vous le moderniserez (c'est pourquoi l'ajouter à l'ancien code est complètement différent de le faire dans un nouveau code).
Donal Fellows
@DonalFellows cela ne veut pas dire mettre en const plus tard. Cela veut dire que vous obtenez les avantages plus tard, lorsque vous lisez le code avec const déjà présent
Caleth
27

Si vous utilisez const rigoureusement, vous seriez surpris du peu de variables réelles dans la plupart des fonctions. Souvent pas plus qu'un compteur de boucle. Si votre code atteint ce point, vous ressentez une sensation de chaleur à l'intérieur ... validation par compilation ... le domaine de la programmation fonctionnelle est proche ... vous pouvez presque le toucher maintenant ...

QBziZ
la source
1
depuis C ++ 17 et la bonté constexpr, j'écris des tests unitaires de temps de compilation ... je me rapproche encore ...
QBziZ
22

const est une promesse que vous faites en tant que développeur et que vous faites appel à l'aide du compilateur pour appliquer.

Mes raisons d'être const-correct:

  • Il communique aux clients de votre fonction que vous ne modifierez pas la variable ou l'objet
  • Accepter des arguments par référence const vous donne l'efficacité de passer par référence avec la sécurité de passer par valeur.
  • L'écriture de vos interfaces comme const correct permettra aux clients de les utiliser. Si vous écrivez votre interface pour prendre des références non-const, les clients qui utilisent const devront rejeter constness afin de travailler avec vous. Ceci est particulièrement ennuyeux si votre interface accepte les caractères non const * et que vos clients utilisent std :: strings, car vous ne pouvez obtenir qu'un caractère const * d'eux.
  • L'utilisation de const demandera au compilateur de vous garder honnête afin que vous ne changiez pas par erreur quelque chose qui ne devrait pas changer.
JohnMcG
la source
20

Ma philosophie est que si vous allez utiliser un langage pointilleux avec des contrôles de temps de compilation, faites-en le meilleur usage possible. constest un moyen imposé par le compilateur de communiquer ce que vous voulez dire ... c'est mieux que les commentaires ou doxygen ne le sera jamais. Vous payez le prix, pourquoi ne pas en déduire la valeur?

Pat Notz
la source
20

Programmer C ++ sans const, c'est comme conduire sans la ceinture de sécurité.

C'est pénible de mettre la ceinture de sécurité chaque fois que vous montez dans la voiture, et 364 jours sur 365, vous arriverez en toute sécurité.

La seule différence est que lorsque vous rencontrez des problèmes avec votre voiture, vous le ressentirez immédiatement, alors qu'avec la programmation sans const, vous devrez peut-être rechercher pendant deux semaines ce qui a causé cet accident pour découvrir que vous avez par inadvertance gâché un argument de fonction qui vous avez passé par référence non const pour plus d'efficacité.

andreas buykx
la source
18

Pour la programmation intégrée, en utilisant const judicieuse lors de la déclaration de structures de données globales peut économiser beaucoup de RAM en faisant en sorte que les données constantes soient situées dans la ROM ou dans la mémoire flash sans copier dans la RAM au moment du démarrage.

Dans la programmation de tous les jours, l'utilisation constprudente vous permet d'éviter d'écrire des programmes qui plantent ou se comportent de manière imprévisible parce qu'ils tentent de modifier les chaînes littérales et d'autres données globales constantes.

Lorsque vous travaillez avec d'autres programmeurs sur de grands projets, une utilisation constcorrecte empêche les autres programmeurs de vous limiter.

bk1e
la source
13

constvous aide à isoler le code qui «change les choses» derrière votre dos. Ainsi, dans une classe, vous marquez toutes les méthodes qui ne changent pas l'état de l'objet comme const. Cela signifie que les constinstances de cette classe ne pourront plus appeler de non- constméthodes. De cette façon, vous êtes empêché d'appeler accidentellement des fonctionnalités susceptibles de modifier votre objet.

Cela constfait également partie du mécanisme de surcharge, vous pouvez donc avoir deux méthodes avec des signatures identiques, mais une avec constet une sans. Celui avec constest appelé pour les constréférences, et l'autre pour les non- constréférences.

Exemple:

#include <iostream>

class HelloWorld {
    bool hw_called;

public:
    HelloWorld() : hw_called(false) {}

    void hw() const {
        std::cout << "Hello, world! (const)\n";
        // hw_called = true;  <-- not allowed
    }

    void hw() {
        std::cout << "Hello, world! (non-const)\n";
        hw_called = true;
    }
};

int
main()
{
    HelloWorld hw;
    HelloWorld* phw1(&hw);
    HelloWorld const* phw2(&hw);

    hw.hw();    // calls non-const version
    phw1->hw(); // calls non-const version
    phw2->hw(); // calls const version
    return 0;
}
Chris Jester-Young
la source
13

l'exactitude de const est l'une de ces choses qui doit vraiment être en place depuis le début. Comme vous l'avez constaté, il est très difficile de l'ajouter plus tard, surtout lorsqu'il y a beaucoup de dépendance entre les nouvelles fonctions que vous ajoutez et les anciennes fonctions non correctes qui existent déjà.

Dans une grande partie du code que j'écris, cela en valait vraiment la peine car nous avons tendance à beaucoup utiliser la composition:

class A { ... }
class B { A m_a; const A& getA() const { return m_a; } };

Si nous n'avions pas de const-correctness, alors vous devriez recourir au renvoi d'objets complexes par valeur afin de vous assurer que personne ne manipulait l'état interne de la classe B derrière votre dos.

En bref, const-correctness est un mécanisme de programmation défensif pour vous sauver de la douleur sur la route.

Peter Kovacs
la source
7

Disons que vous avez une variable en Python. Vous savez que vous n'êtes pas censé le modifier. Et si vous le faites accidentellement?

C ++ vous donne un moyen de vous protéger de faire accidentellement quelque chose que vous n'étiez pas censé pouvoir faire en premier lieu. Techniquement, vous pouvez le contourner de toute façon, mais vous devez faire un travail supplémentaire pour vous tirer dessus.

Greg Rogers
la source
4

Il y a un bel article ici sur const en c ++. C'est une opinion assez simple, mais j'espère que cela en aidera certains.

Ólafur Waage
la source
3

Lorsque vous utilisez le mot-clé "const", vous spécifiez une autre interface pour vos classes. Il existe une interface qui inclut toutes les méthodes et une interface qui inclut uniquement les méthodes const. Évidemment, cela vous permet de restreindre l'accès à certaines choses que vous ne voulez pas changer.

Oui, cela devient plus facile avec le temps.

Wesley Tarle
la source
2

J'aime la correction de const ... en théorie. À chaque fois que j'ai essayé de l'appliquer rigoureusement dans la pratique, il est finalement tombé en panne et const_cast commence à se faufiler en rendant le code laid.

C'est peut-être juste les modèles de conception que j'utilise, mais const finit toujours par être un pinceau trop large.

Par exemple, imaginez un moteur de base de données simple ... il a des objets de schéma, des tables, des champs, etc. Un utilisateur peut avoir un pointeur 'const Table' signifiant qu'il n'est pas autorisé à modifier le schéma de table lui-même ... mais qu'en est-il de la manipulation les données associées à la table? Si la méthode Insert () est marquée const, elle doit en interne convertir la const-ness pour manipuler réellement la base de données. S'il n'est pas marqué const, il ne protège pas contre l'appel de la méthode AddField.

Peut-être que la réponse est de diviser la classe en fonction des exigences de const-ness, mais cela a tendance à compliquer la conception plus que je ne le souhaiterais pour l'avantage qu'elle apporte.

Rob Walker
la source
Je pense que votre exemple est un cas d'utilisation excessive de const, mais n'oubliez pas le modificateur mutable, qui peut être appliqué aux variables d'instance pour supprimer la const-ness.
Zooba
2
Quand une fonction Insert () serait-elle marquée const à moins qu'elle ne soit mal nommée? L'ajout d'éléments modifie généralement l'élément auquel vous l'avez ajouté, ce qui signifie qu'il n'est pas constant. Ce que vous vouliez vraiment, c'était un TableWithConstSchema.
Greg Rogers
Je pourrais ajouter une autre classe, mais je ne veux pas rendre l'API inutilement complexe uniquement pour des raisons de const-correctness.
Rob Walker du
1

Vous pouvez également donner des conseils au compilateur avec const .... selon le code suivant

#include <string>

void f(const std::string& s)
{

}
void x( std::string& x)
{
}
void main()
{
    f("blah");
    x("blah");   // won't compile...
}
Keith Nicholas
la source