Alors, pourquoi 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'y arrive du point de vue python: si vous ne voulez pas que quelque chose soit changé, ne le changez pas. Donc, cela étant dit, voici quelques des questions:
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 être const aussi. Ensuite, cela me oblige à changer n autre fonction ailleurs. Est-ce quelque chose qui devient plus facile avec l'expérience?
Les avantages de const vraiment sont-ils 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 suis plus concentré 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 en termes de performances.
Il s'agit de l'article définitif sur la "constance correcte": https://isocpp.org/wiki/faq/const-correctness .
En résumé, utiliser const est une bonne pratique car ...
Le compilateur peut l'optimiser. Par exemple, vous êtes protégé contre
if( x = y ) // whoops, meant if( x == y )
Dans le même temps, le compilateur peut générer du 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, car il peut être difficile d'utiliser systématiquement const-correctness, mais le code final est plus concis et plus sûr à programmer. Lorsque vous effectuez beaucoup de développement C++, les avantages de cela se manifestent rapidement.
Voici un morceau de code avec une erreur courante contre laquelle l'exactitude peut vous protéger:
void foo(const int DEFCON)
{
if (DEFCON = 1) //< FLAGGED AS COMPILER ERROR! WORLD SAVED!
{
fire_missiles();
}
}
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 être const aussi. 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 du code const-correct, bien sûr. Si vous concevez const-correct dès le départ, cela ne devrait JAMAIS être un problème. Si vous faites quelque chose de const et que quelque chose d'autre ne se conforme pas, le compilateur vous dit quelque chose d'extrêmement important, et vous devriez prendre le temps de le réparer correctement.
Ce n'est pas pour vous lorsque vous écrivez le code au départ. 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 à en tirer.
Si vous utilisez rigoureusement const, vous seriez surpris du peu de variables réelles présentes dans la plupart des fonctions. Souvent rien de plus qu'un compteur de boucles. Si votre code atteint ce point, vous obtenez une sensation chaleureuse à l'intérieur ... validation par compilation ... le domaine de la programmation fonctionnelle est à proximité ... vous pouvez presque le toucher maintenant ...
const est une promesse que vous faites en tant que développeur, et sollicitez l'aide du compilateur pour l'appliquer.
Mes raisons d'être const-correct:
Programmer C++ sans const, c'est comme conduire sans la ceinture de sécurité.
C'est difficile 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 ressentez immédiatement, alors qu'avec la programmation sans const, vous devrez peut-être rechercher pendant deux semaines ce qui a provoqué 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é.
Ma philosophie est que si vous allez utiliser un langage pointilleux avec des vérifications de temps de compilation, faites-en le meilleur usage possible. const
est un moyen imposé par le compilateur de communiquer ce que vous signifie ... c'est mieux que des commentaires ou doxygen le sera jamais. Vous payez le prix, pourquoi ne pas en tirer la valeur?
Pour la programmation intégrée, l'utilisation judicieuse de const
lors de la déclaration de structures de données globales peut économiser beaucoup de RAM en provoquant la localisation des données constantes dans ROM = ou flasher sans copier dans RAM au démarrage).
Dans la programmation quotidienne, l'utilisation de const
vous aide à éviter d'écrire des programmes qui se bloquent ou se comportent de manière imprévisible car ils tentent de modifier les littéraux de chaîne et d'autres données globales constantes.
Lorsque vous travaillez avec d'autres programmeurs sur de grands projets, l'utilisation de const
correctement empêche les autres programmeurs de vous étrangler.
l'exactitude constante 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 const-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 retour d'objets complexes par valeur afin de vous assurer que personne ne manipule 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.
const
vous aide à isoler le code qui "change les choses" derrière votre dos. Ainsi, dans une classe, vous marquez toutes les méthodes qui ne modifient pas l'état de l'objet comme const
. Cela signifie que les instances const
de cette classe ne pourront plus appeler de méthodes nonconst
. De cette façon, vous ne pouvez pas appeler accidentellement des fonctionnalités susceptibles de modifier votre objet.
De plus, const
fait partie du mécanisme de surcharge, vous pouvez donc avoir deux méthodes avec des signatures identiques, mais une avec const
et une sans. Celui avec const
est appelé pour les références const
, et l'autre est appelé pour les références nonconst
.
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;
}
Supposons que vous ayez une variable en Python. Vous savez que vous n'êtes pas supposé pour le modifier. Et si vous le faites accidentellement?
C++ vous donne un moyen de vous protéger contre toute action accidentelle que vous n'étiez pas censé être capable de 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.
Il y a un bel article ici sur const en c ++. C'est une opinion assez simple mais j'espère que cela aide certains.
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 souhaitez pas modifier.
Oui, cela devient plus facile avec le temps.
J'aime l'exactitude des const ... en théorie. À chaque fois que j'ai essayé de l'appliquer rigoureusement dans la pratique, il s'est finalement décomposé et const_cast commence à se glisser dans la laideur du code.
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 rejeter la constance pour réellement manipuler 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.
La réponse est peut-être de diviser la classe en fonction des exigences de constance, mais cela a tendance à compliquer la conception plus que je ne le souhaiterais pour l'avantage qu'elle apporte.
Vous pouvez également donner des astuces 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...
}