Sémantique C ++ de `static const` vs` const`

149

En C ++ spécifiquement, quelles sont les différences sémantiques entre par exemple:

static const int x = 0 ;

et

const int x = 0 ;

à la fois staticen tant que lien et spécificateur de classe de stockage (c'est-à-dire à l'intérieur et à l'extérieur d'une fonction).

Clifford
la source
7
staticest probablement le mot clé le plus surchargé en C ++. La signification de votre code varie considérablement selon qu'il s'agit de la portée de l'espace de noms, de la portée de la classe ou de la portée de la fonction. Vous voudrez peut-être clarifier cela.
sbi le
1
@sbi: Je pensais déjà l'avoir fait. Portée de la fonction (où il s'agit d'un spécificateur de classe de stockage) et étendue du fichier (où il s'agit d'un spécificateur de liaison). Les membres de la classe et les variables de portée de l'espace de noms ne me préoccupent pas spécifiquement en ce qui concerne cette question, bien que si quelqu'un pense qu'il y a une distinction intéressante, n'hésitez pas à la couvrir également.
Clifford le
@Clifford: Je suis désolé d'avoir oublié ces derniers mots. Cependant, cela a révélé un malentendu de votre part: en C ++, la portée du fichier est la portée de l'espace de noms. Si vous déclarez quelque chose en dehors de n'importe quel espace de noms, il appartiendra simplement à l' espace de noms global (et est accessible via un préfixé ::sans identifiant devant). Je ne suis pas au courant de différences significatives entre l'espace de noms global et les espaces de noms qui y sont imbriqués. Il n'y a certainement aucun staticobjet concernant .
sbi le
1
le lien est différent de la visibilité , en les utilisant de manière interchangeable, vous allez confondre les personnes à qui vous parlez et probablement aussi vous-même.
Ben Voigt
1
@Ben, @sbi: Je n'avais pas l'intention de suggérer que la portée du fichier et le lien statique étaient les mêmes, simplement que le lien statique implique la portée du fichier. En ce sens, la portée (ou visibilité) est un attribut de lien statique et externe, et non un synonyme de l'un ou de l'autre. Je pense que la question initiale reste claire et bien formulée, et que nous discutons simplement des commentaires faits en réponse à la remarque quelque peu condescendante de sbi. Nous discutons ici de sémantique imprécise de l'anglais plutôt que de ma compréhension, donc je pense que nous pouvons nous arrêter.
Clifford le

Réponses:

128

Au niveau du fichier, aucune différence en C ++. constfait de la liaison interne la valeur par défaut et toutes les variables globales ont une durée de vie statique. Mais la première variante a le même comportement en C, ce qui peut être une bonne raison de l'utiliser.

Dans une fonction, la deuxième version peut être calculée à partir de paramètres. En C ou C ++, il n'est pas nécessaire que ce soit une constante de compilation comme l'exigent certains autres langages.

Au sein d'une classe, fondamentalement la même chose que pour les fonctions. Une constvaleur d' instance peut être calculée dans la liste ctor-initializer . A static constest défini lors de l'initialisation du démarrage et reste inchangé pour le reste du programme. (Remarque: le code des staticmembres est un peu différent car la déclaration et l'initialisation sont séparées.)

Rappelez-vous, en C ++, constsignifie lecture seule , pas constante . Si vous avez un pointeur vers, d' constautres parties du programme peuvent changer la valeur pendant que vous ne cherchez pas. Si la variable a été définie avec const, personne ne peut la modifier après l'initialisation, mais l'initialisation peut toujours être arbitrairement complexe.

Ben Voigt
la source
1
Y a-t-il quelque chose appelé portée de fichier? Je vérifiais juste 3,3 $ et je pense que le plus proche est «la portée de l'espace de noms». Ma compréhension est-elle correcte? La norme C ++ 03 mentionne la portée du fichier uniquement dans les annexes
Chubsdad
2
Je suggérerais que la portée du fichier est un artefact de l'éditeur de liens plutôt que du compilateur, donc peut ne pas attirer beaucoup d'attention dans la norme de langage. Strictement c'est probablement "la portée de l'unité de compilation".
Clifford
8
+1 pour la phrase "const signifie lecture seule, non constante", c'est-à-dire "Compilateur, si vous voyez quelqu'un essayer de modifier ce const, aboie très fort." C'est la raison pour laquelle quelque chose peut être constant et volatil en même temps.
Dan
5
C'est plus "Compilateur, si vous me voyez essayer de modifier cette chose const (ou donner la permission à quelqu'un d'autre de le faire)", aboie très fort. Dans la plupart des contextes, consts'applique à une vue de la variable et non à la variable elle-même, quelqu'un d'autre peut avoir une non- constvue de la même variable, et le compilateur sera assez silencieux lorsqu'il la modifiera.
Ben Voigt
1
@Ben: Pour être clair, C ++ 0x ne supprime pas cette utilisation particulière de const, mais le nouveau constexprpeut être utilisé à la place (et dans d'autres scénarios également). En fait, la norme C ++ 0x étend également la possibilité d'utiliser constdans ce scénario à des "types littéraux" non intégraux. Je pense que je préférerais utiliser constexprpour ces cas, car vous rompriez de toute façon la compatibilité descendante avec les compilateurs pré-C ++ 0x.
Michael Burr
4

Projet de norme C ++ 17 sur constimplique staticà la portée du fichier

Voici la citation de ce qui a été mentionné sur: https://stackoverflow.com/a/3709257/895245

C ++ 17 n4659 standard draft 6.5 "Programme et liaison":

3 Un nom ayant une portée d'espace de noms (6.3.6) a un lien interne s'il s'agit du nom de

  • (3.1) - une variable, une fonction ou un modèle de fonction qui est explicitement déclaré statique; ou,
  • (3.2) - une variable non en ligne de type qualifié const non volatile qui n'est ni explicitement déclarée extern ni précédemment déclarée comme ayant un lien externe; ou
  • (3.3) - un membre de données d'un syndicat anonyme.

Annexe C (informative) Compatibilité, C.1.2 Clause 6: "concepts de base" explique pourquoi cela a été remplacé par C:

6.5 [également 10.1.7]

Changement: Un nom de portée de fichier qui est explicitement déclaré const, et non explicitement déclaré extern, a un lien interne, tandis qu'en C il aurait un lien externe.

Justification: étant donné que les objets const peuvent être utilisés comme valeurs lors de la traduction en C ++, cette fonctionnalité incite les programmeurs à fournir un initialiseur explicite pour chaque objet const. Cette fonction permet à l'utilisateur de placer des objets const dans des fichiers source qui sont inclus dans plusieurs unités de traduction.

Effet sur la fonction d'origine: passez à la sémantique de la fonction bien définie.

Difficulté de conversion: transformation sémantique.

Quelle est la fréquence d'utilisation: rarement.

Voir aussi: Pourquoi const implique-t-il une liaison interne en C ++, alors que ce n'est pas le cas en C?

Ce que vous voulez probablement faire à la place sur les en-têtes

Expliqué en détail sur: Que signifie «const static» en C et C ++?

  • pré C ++ 17: externdans l'en-tête, définition dans le fichier cpp
  • post C ++ 17: variable en ligne sur l'en-tête
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
la source
Merci, bien que je ne pense pas que ce soit une chance dans C ++ 17 par rapport même à C ++ 98, et la question a été posée en 2010. De plus, votre réponse ne traite que de la statique comme spécificateur de liaison (à la portée de l'espace de noms) , et la question posée spécifiquement sur la sémantique dans différents contextes.
Clifford
@Clifford oui, certainement plus ancien que C ++ 17, juste paresseux pour lire toutes les normes ;-) Clarifiera la partie portée du fichier.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功