Quelle est la meilleure façon d'initialiser un membre de données statique privé en C ++? J'ai essayé cela dans mon fichier d'en-tête, mais cela me donne d'étranges erreurs de l'éditeur de liens:
class foo
{
private:
static int i;
};
int foo::i = 0;
Je suppose que c'est parce que je ne peux pas initialiser un membre privé en dehors de la classe. Alors, quelle est la meilleure façon de procéder?
c++
initialization
static-members
Jason Baker
la source
la source
inline static int x[] = {1, 2, 3};
. Voir en.cppreference.com/w/cpp/language/static#Static_data_membersRéponses:
La déclaration de classe doit se trouver dans le fichier d'en-tête (ou dans le fichier source s'il n'est pas partagé).
Fichier: foo.h
Mais l'initialisation doit être dans le fichier source.
Fichier: foo.cpp
Si l'initialisation se trouve dans le fichier d'en-tête, alors chaque fichier qui inclut le fichier d'en-tête aura une définition du membre statique. Ainsi, pendant la phase de liaison, vous obtiendrez des erreurs de l'éditeur de liens car le code pour initialiser la variable sera défini dans plusieurs fichiers source. L'initialisation du
static int i
doit se faire en dehors de toute fonction.Note: Matt Curtis: rappelle que C ++ permet la simplification de ce qui précède , si la variable membre statique est de type const int (par exemple
int
,bool
,char
). Vous pouvez ensuite déclarer et initialiser la variable membre directement à l'intérieur de la déclaration de classe dans le fichier d'en-tête:la source
Pour une variable :
foo.h:
foo.cpp:
En effet, il ne peut y avoir qu'une seule instance de
foo::i
dans votre programme. C'est en quelque sorte l'équivalent deextern int i
dans un fichier d' en-tête etint i
dans un fichier source.Pour une constante, vous pouvez mettre la valeur directement dans la déclaration de classe:
la source
private
variables peuvent être initialisées en dehors de Class ici, cela peut-il être fait pour les variables non statiques également.Class
n'a aucun sens dans Cpp.Depuis C ++ 17, les membres statiques peuvent être définis dans l'en-tête avec le mot clé inline .
http://en.cppreference.com/w/cpp/language/static
"Un membre de données statiques peut être déclaré en ligne. Un membre de données statiques en ligne peut être défini dans la définition de classe et peut spécifier un initialiseur de membre par défaut. Il n'a pas besoin d'une définition hors classe:"
la source
Pour les futurs téléspectateurs de cette question, je tiens à souligner que vous devez éviter ce que suggère monkey0506 .
Les fichiers d'en-tête sont destinés aux déclarations.
Les fichiers d'en-tête sont compilés une fois pour chaque
.cpp
fichier qui les a directement ou indirectement#includes
, et le code en dehors de toute fonction est exécuté avant l'initialisation du programmemain()
.En mettant:
foo::i = VALUE;
dans l'en-tête,foo:i
sera attribuée la valeurVALUE
(quelle qu'elle soit) pour chaque.cpp
fichier, et ces affectations se produiront dans un ordre indéterminé (déterminé par l'éditeur de liens) avant l'main()
exécution.Et si nous devions
#define VALUE
être un numéro différent dans l'un de nos.cpp
fichiers? Il compilera très bien et nous n'aurons aucun moyen de savoir lequel gagnera jusqu'à ce que nous exécutions le programme.Ne jamais mettre le code exécuté dans un en- tête pour la même raison que vous ne
#include
un.cpp
fichier.inclure des gardes (que je conviens que vous devriez toujours utiliser) vous protègent de quelque chose de différent: le même en-tête étant indirectement
#include
plusieurs fois d lors de la compilation d'un seul.cpp
fichierla source
Avec un compilateur Microsoft [1], des variables statiques qui ne sont pas
int
similaires peuvent également être définies dans un fichier d'en-tête, mais en dehors de la déclaration de classe, à l'aide de Microsoft specific__declspec(selectany)
.Notez que je ne dis pas que c'est bon, je dis simplement que cela peut être fait.
[1] De nos jours, plus de compilateurs que le support MSC
__declspec(selectany)
- au moins gcc et clang. Peut-être même plus.la source
Est la syntaxe correcte pour initialiser la variable, mais elle doit aller dans le fichier source (.cpp) plutôt que dans l'en-tête.
Puisqu'il s'agit d'une variable statique, le compilateur n'a besoin d'en créer qu'une seule copie. Vous devez avoir une ligne "int foo: i" quelque part dans votre code pour indiquer au compilateur où le mettre sinon vous obtenez une erreur de lien. Si cela se trouve dans un en-tête, vous obtiendrez une copie dans chaque fichier qui comprend l'en-tête, alors obtenez des erreurs de symboles définies multipliées de l'éditeur de liens.
la source
Je n'ai pas assez de représentants ici pour ajouter ceci en tant que commentaire, mais à mon avis, c'est un bon style d'écrire vos en-têtes avec les gardes #include de toute façon, ce qui, comme l'a noté Paranaix il y a quelques heures, empêcherait une erreur de définition multiple. À moins que vous n'utilisiez déjà un fichier CPP distinct, il n'est pas nécessaire d'en utiliser un uniquement pour initialiser les membres statiques non intégraux.
Je ne vois pas la nécessité d'utiliser un fichier CPP distinct pour cela. Bien sûr, vous pouvez, mais il n'y a aucune raison technique pour laquelle vous devriez le faire.
la source
#endif // FOO_H
#pragma once
Si vous voulez initialiser un type composé (fe chaîne), vous pouvez faire quelque chose comme ça:
Comme la méthode
ListInitializationGuard
est une variable statique à l'intérieurSomeClass::getList()
, elle ne sera construite qu'une seule fois, ce qui signifie que le constructeur est appelé une seule fois. Celainitialize _list
variera selon la valeur dont vous avez besoin. Tout appel ultérieur àgetList
retournera simplement un_list
objet déjà initialisé .Bien sûr, vous devez
_list
toujours accéder à l' objet en appelant lagetList()
méthode.la source
Modèle de constructeur statique C ++ 11 qui fonctionne pour plusieurs objets
Un idiome a été proposé sur: https://stackoverflow.com/a/27088552/895245 mais voici une version plus propre qui ne nécessite pas de créer une nouvelle méthode par membre.
main.cpp
GitHub en amont .
Compiler et exécuter:
Voir aussi: constructeurs statiques en C ++? J'ai besoin d'initialiser des objets statiques privés
Testé sur Ubuntu 19.04.
Variable en ligne C ++ 17
Mentionné à: https://stackoverflow.com/a/45062055/895245 mais voici un exemple exécutable multifichier pour le rendre encore plus clair: Comment fonctionnent les variables en ligne?
la source
Vous pouvez également inclure l'affectation dans le fichier d'en-tête si vous utilisez des protections d'en-tête. J'ai utilisé cette technique pour une bibliothèque C ++ que j'ai créée. Une autre façon d'obtenir le même résultat consiste à utiliser des méthodes statiques. Par exemple...
Le code ci-dessus a le "bonus" de ne pas nécessiter de fichier CPP / source. Encore une fois, une méthode que j'utilise pour mes bibliothèques C ++.
la source
Je suis l'idée de Karl. Je l'aime et maintenant je l'utilise aussi. J'ai un peu changé la notation et ajouté quelques fonctionnalités
cela produit
la source
Fonctionne également dans le fichier privateStatic.cpp:
la source
Et une
set_default()
méthode?Nous n'aurions qu'à utiliser la
set_default(int x)
méthode et notrestatic
variable serait initialisée.Ce ne serait pas en désaccord avec le reste des commentaires, en fait, cela suit le même principe d'initialisation de la variable dans une portée globale, mais en utilisant cette méthode, nous la rendons explicite (et facile à voir-comprendre) au lieu d'avoir la définition de la variable qui pend là.
la source
Le problème de l'éditeur de liens que vous avez rencontré est probablement dû à:
Il s'agit d'un problème courant pour ceux qui commencent par C ++. Le membre de classe statique doit être initialisé dans une seule unité de traduction, c'est-à-dire dans un fichier source unique.
Malheureusement, le membre de classe statique doit être initialisé en dehors du corps de classe. Cela complique l'écriture de code uniquement en-tête et, par conséquent, j'utilise une approche assez différente. Vous pouvez fournir votre objet statique via une fonction de classe statique ou non statique, par exemple:
la source
Une façon «ancienne» de définir des constantes consiste à les remplacer par
enum
:De cette façon , ne nécessite pas de donner une définition et évite de faire la constante lvalue , ce qui peut vous faire économiser quelques maux de tête, par exemple lorsque vous avez accidentellement ODR utiliser ce.
la source
Je voulais juste mentionner quelque chose d'un peu étrange pour moi lorsque j'ai rencontré cela pour la première fois.
J'avais besoin d'initialiser un membre de données statiques privé dans une classe de modèle.
dans le .h ou .hpp, cela ressemble à ceci pour initialiser un membre de données statiques d'une classe de modèle:
la source
Cela sert-il votre objectif?
la source