Pour commencer, vous savez probablement que cela const
peut être utilisé pour rendre les données d'un objet ou un pointeur non modifiables ou les deux.
const Object* obj; // can't change data
Object* const obj; // can't change pointer
const Object* const obj; // can't change data or pointer
Cependant, vous pouvez également utiliser la syntaxe:
Object const *obj; // same as const Object* obj;
La seule chose qui semble avoir de l'importance, c'est de quel côté de l'astérisque vous mettez le const
mot - clé. Personnellement, je préfère mettre const
à gauche du type pour spécifier que les données ne sont pas modifiables car je trouve qu'elles se lisent mieux dans mon état d'esprit de gauche à droite, mais quelle syntaxe est venue en premier?
Plus important encore, pourquoi y a-t-il deux façons correctes de spécifier les const
données et dans quelle situation préféreriez-vous ou auriez-vous besoin de l'une par rapport à l'autre, le cas échéant?
Éditer:
Il semble donc que ce soit une décision arbitraire lorsque la norme sur la façon dont les compilateurs doivent interpréter les choses a été rédigée bien avant ma naissance. Depuis const
est appliqué à ce qui est à gauche du mot-clé (par défaut?) Je suppose qu'ils ont pensé qu'il n'y avait aucun mal à ajouter des "raccourcis" pour appliquer des mots-clés et des qualificatifs de type d'une autre manière au moins jusqu'à ce que la déclaration change par analyse d'un * ou & ...
C'était aussi le cas en C alors je suppose?
const
après le type, par exemple#define MAKE_CONST(T) T const
au lieu de#define MAKE_CONST(T) const T
pour que celaMAKE_CONST(int *)
se développe correctement versint * const
au lieu deconst int *
.Réponses:
Essentiellement, la raison pour laquelle la position des
const
spécificateurs à l'intérieur avant un astérisque n'a pas d'importance est que la grammaire C a été définie de cette façon par Kernighan et Ritchie.La raison pour laquelle ils ont défini la grammaire de cette manière était probablement que leur compilateur C analysait l'entrée de gauche à droite et avait fini de traiter chaque jeton au fur et à mesure qu'il consommait cela. La consommation du
*
jeton change l'état de la déclaration actuelle en un type de pointeur. Rencontreconst
après*
signifie que leconst
qualificatif est appliqué à une déclaration de pointeur; le rencontrer avant le*
moyen auquel le qualificatif est appliqué aux données pointées.Parce que la signification sémantique ne change pas si le
const
qualificatif apparaît avant ou après les spécificateurs de type, il est accepté dans les deux cas.Un cas similaire se produit lors de la déclaration de pointeurs de fonction, où:
void * function1(void)
déclare une fonction qui retournevoid *
,void (* function2)(void)
déclare un pointeur de fonction vers une fonction qui renvoievoid
.Encore une fois, la chose à noter est que la syntaxe du langage prend en charge un analyseur de gauche à droite.
la source
*
analyseur du compilateur ne sache qu'il s'agit d'un pointeur, il est donc constant pour la valeur des données. Après *, il est lié au pointeur constant. Brillant. Et enfin ça explique pourquoi je peux faireconst char
aussi bien quechar const
.const
vienne toujours après la chose qu'il qualifie ... exactement pour que je puisse toujours terminer le traitement du const immédiatement après l'avoir consommé. Cela semble donc être un argument pour interdire West-Const, plutôt que de l'autoriser.++
opérateur? "La phrase", à mon humble avis, m'a aidé à réaliser qu'il n'y avait aucune raison particulière autre que parce qu'ils le pouvaient. Peut-être qu'ils feraient un choix différent aujourd'hui / peut-être pas.La règle est:
Je préfère utiliser const à droite de la chose pour être const juste parce que c'est la manière «originale» de définir const.
Mais je pense que c'est un point de vue très subjectif.
la source
Object const *
un pointeur vers un objet const. Si vous mettez leconst
sur la gauche, il se lirait comme un pointeur vers un objet qui est const, qui ne coule pas vraiment très bien.const
n'est pas une classe de stockage, mais les gens ne sont pas des analyseurs).Je préfère la deuxième syntaxe. Cela m'aide à garder une trace de `` quoi '' est constant en lisant la déclaration de type de droite à gauche:
la source
Object const* const
pasconst const Object*
. "const" ne peut pas être à gauche sauf dans le cas particulier où tant de gens l'aiment absolument. (Voir Heath ci-dessus.)L'ordre des mots-clés dans une déclaration n'est pas tout à fait fixe. Il existe de nombreuses alternatives au «seul vrai ordre». Comme ça
ou devrait-il être
??
la source
decl-specifier-seq
est une séquence dedecl-specifier
s. Il n'y a pas d'ordre donné par la grammaire, et le nombre d'occurrences pour chaque mot-clé n'est limité que par quelques règles sémantiques (vous pouvez en avoir unconst
mais deuxlong
:-)unsigned
est un type, le même queunsigned int
etint unsigned
.unsigned long
est un autre type, le même queunsigned long int
etint long unsigned
. Vous voyez le modèle?;)
. OK, mercistatic
au fouillis de mots, mais ce n'est que récemment que les compilateurs se sont plaints du fait qu'ilstatic
fallait passer en premier.La première règle consiste à utiliser le format requis par vos normes de codage locales. Après cela: mettre le
const
devant ne mène à aucune confusion lorsque des typedefs sont impliqués, par exemple:Si votre standard de codage autorise les typedef de pointeurs, alors il devrait vraiment insister pour mettre le const après le type. Dans tous les cas, sauf lorsqu'il est appliqué au type, const doit suivre ce à quoi il s'applique, donc la cohérence plaide également en faveur de la const après. Mais les directives de codage locales l'emportent sur tous ces éléments; la différence n'est normalement pas assez importante pour revenir en arrière et modifier tout le code existant.
la source
const std::string::const_iterator
aussi bien pour faire bonne mesure;)const IntPtr p1
éventuellement signifier autre que "pointeur entier constant" (c'est-à-dire "pointeur constant vers entier")? Personne dans son bon sens, même sans savoir commentIntPtr
est défini, ne penserait quep1
c'est mutable. Et d'ailleurs, pourquoi quelqu'un supposerait-il à tort que*p1
c'est immuable? De plus, mettre le const ailleurs (par exempleIntPtr const p1
) ne change pas du tout la sémantique.std::vector<T>::const_iterator
, où ce n'est pas l'itérateur qui est const, mais vers quoi il pointe).Il y a des raisons historiques pour lesquelles la gauche ou la droite est acceptable. Stroustrup avait ajouté const au C ++ en 1983 , mais il ne l'a fait en C qu'en C89 / C90.
En C ++, il y a une bonne raison de toujours utiliser const sur la droite. Vous serez cohérent partout car les fonctions membres const doivent être déclarées de cette façon:
la source
const int& getInt();
int& const getInt();
int const& getInt();
c'est mieux que l'équivalentconst int& getInt();
alorsint& const getInt();
que le comparer avec est redondant (les références sont déjà const) bien que légal et donnera généralement un avertissement. Quoi qu'il en soit, const sur une fonction membre change lethis
pointeur de la fonction deFoo* const
àFoo const* const
.const
sur une fonction membre ne signifie pas du tout la même chose - ou est-cevoid set(int)&;
une sorte de référence à une fonction?