2010-11-25 2 views
10

Encore une autre static question. J'ai lu ce qui suit:mot-clé statique dans le fichier h et le lien interne

Et je ne comprennent pas encore le comportement suivant: J'ai un fichier h:

// StaticTest.h 
#include <stdio.h> 

static int counter = 0; 

struct A { 
    A() { 
     counter++; 
     printf("In A's ctor(%d)\n", counter); 
    } 
    ~A() { 
     counter--; 
     printf("In A's dtor(%d)\n", counter); 
    } 
}; 

static A a; 

Et deux fichiers cpp:

// StaticTest1.cpp 
#include "StaticTest.h" 

int main() { 
return 0; 
} 

Et:

// StaticTest2.cpp 
#include "StaticTest.h" 

La sortie du programme est:

In A's ctor(1) 
In A's ctor(2) 
In A's dtor(1) 
In A's dtor(0) 

Maintenant, le constructeur de A est appelé deux fois, depuis le h fichier est inclus deux fois, et puisque l'instance A nommée a est déclarée static, elle a un lien interne et le compilateur est heureux. Comme le counter est également déclaré statique, il a également une liaison interne, et je suppose que sa valeur ne sera pas partagée dans les deux fichiers cpp --- mais la sortie du programme implique que la valeur est partagée, car elle compte jusqu'à 2

des idées?

EDIT: Toutes les réponses concernant ce qui est considéré comme une « bonne habitude de programmation » dans le contexte de la déclaration des variables statiques dans h par rapport à cpp fichiers est également accueillie favorablement.

+0

Je veux * * dire quelque chose au sujet des détails de mise en œuvre et sur les valeurs statiques initialisées à la compilation versus valeurs statiques initialisées exécution, mais je ne suis pas sûr de l'afficher comme réponse. Essayez de ne pas initialiser 'counter' et de l'initialiser dans' main() '. –

+0

@ Benoit Thiery: C'est le code source complet. –

+0

@ Ignacio Vazquez-Abrams: de la page MSDN: "Lorsque vous déclarez une variable, la variable a une durée statique et le compilateur l'initialise à 0 sauf si vous spécifiez une autre valeur" –

Répondre

9

Si StaticTest.h est partagé entre les fichiers source de différence, vous obtiendrez un comportement indéfini. Si vous définissez une classe ou des fonctions en ligne dans différentes unités de traduction, alors leurs définitions doivent être les mêmes (même séquence de jetons) et, fondamentalement, tout identificateur doit faire référence à la même entité (sauf un objet const avec lien interne) comme dans la définition dans une autre unité de traduction.

Vous violez cela parce que counter a une liaison interne donc dans différentes unités de traduction, l'identificateur dans les définitions de fonctions fait référence à un objet différent.

Référence: C++ 03 3.2 [basic.def.odr]/5.

+1

+1 C++ est un langage difficile :) –

+1

Je ne suis pas sûr de comprendre complètement votre réponse - 'counter' n'est pas une définition de classe, c'est une déclaration de variable, et de toute façon, ce n'est pas un lien interne que je peux avoir deux entités, chacune dans sa propre unité de traduction? –

+3

@Itamar Katz: Oui, vous avez plus d'une entité appelée 'counter' (chacune avec un lien interne), mais vous violez l'ODR sur la définition de' A', 'A :: A' et' A :: ~ A'. Bien que vos définitions se composent des mêmes séquences symboliques (bonnes), parce que 'counter' a un lien interne, lorsque vous utilisez cet identificateur dans la définition de' A', il fait référence à un objet différent dans chaque unité de traduction séparée. Cela signifie que les définitions de 'A' ne sont pas les mêmes pour toutes les unités de traduction qui violent l'ODR. –

Questions connexes