52 votes

Qu'est-ce qui fait qu'une variable statique ne s'initialise qu'une seule fois?

J'ai remarqué que si vous initialisez une variable statique en C ++ dans le code, l'initialisation ne s'exécute que la première fois que vous exécutez la fonction.

C'est cool, mais comment est-ce mis en œuvre? Cela se traduit-il par une sorte de déclaration tordue si? (si on lui donne une valeur, alors ..)

 void go( int x )
{
    static int j = x ;
    cout << ++j << endl ; // see 6, 7, 8
} 

int main()
{
    go( 5 ) ;
    go( 5 ) ;
    go( 5 ) ; 
}
 

59voto

AndreyT Points 139512

Oui, il n'a normalement se traduire par une implicite if déclaration avec une interne indicateur booléen. Ainsi, dans la plupart des applications de base de votre déclaration se traduit normalement par quelque chose comme

void go( int x ) {
  static int j;
  static bool j_initialized;

  if (!j_initialized) {
    j = x;
    j_initialized = true;
  }

  ...
} 

En plus de cela, si votre objet statique est un non-trivial destructeur, la langue doit obéir à une autre règle: ces objets statiques doivent être détruits dans l'ordre inverse de leur construction. Depuis la construction de l'ordre n'est connue qu'au moment de l'exécution, la destruction de l'ordre est défini au moment de l'exécution ainsi. Donc, chaque fois que vous construisez un local objet statique non triviale destructeur, le programme doit s'inscrire dans une sorte de linéaire conteneur, qui sera, plus tard, les utiliser pour détruire ces objets dans le bon ordre.

Inutile de dire, les détails réels dépendent de la mise en œuvre.


Il convient d'ajouter que lorsqu'il s'agit d'objets statiques de "primitifs" types (comme int dans votre exemple) initialisé avec des constantes de compilation, le compilateur est libre pour initialiser cet objet au démarrage. Jamais vous ne verrez la différence. Toutefois, si vous prenez un exemple plus complexe avec un "non-primitif" de l'objet

void go( int x ) {
  static std::string s = "Hello World!";
  ...

ensuite, l'approche ci-dessus avec if est ce que vous devriez vous attendre à trouver dans le code généré, même lorsque l'objet est initialisé avec une constante de compilation.

Dans votre cas, l'initialisation n'est pas connu au moment de la compilation, ce qui signifie que le compilateur a pour retarder l'initialisation et l'utilisation que l'implicite if.

7voto

Jon Points 194296

Oui, le compilateur génère généralement un booléen caché "a-t-il été initialisé?" et un if qui s'exécute à chaque exécution de la fonction.

Il y a plus de matériel de lecture ici: Comment l'initialisation des variables statiques est-elle implémentée par le compilateur?

3voto

Tony D Points 43962

Alors qu'il est en effet "une sorte de tordu, si", la torsion peut être plus que vous ne l'imaginiez...

ZoogieZork commentaire de AndreyT la réponse de touche sur un aspect important: l' initialisation des variables locales statiques - sur certains compilateurs y compris GCC - est par défaut thread-safe (un compilateur de ligne de commande option peut le désactiver). Par conséquent, c'est à l'aide de certains inter-threads synchronisation (un mutex ou opération atomique de certains types) qui peut être relativement lente. Si vous n'êtes pas à l'aise - performance sage - avec l'utilisation explicite d'une telle opération dans votre fonction, alors vous devriez considérer si il y a une incidence moindre alternative à la paresse de l'initialisation de la variable (c'est à dire construire explicitement dans un thread-safe façon vous-même quelque part, juste une fois). Très peu de fonctions sont donc sensible aux performances que ce questions de bien - ne les laissez pas gâcher votre journée, ou de rendre votre code plus compliqué, à moins que vos programmes trop lent et votre profiler du doigté de la région.

1voto

Jeffrey Faust Points 247

Ils ne sont initialisés qu'une seule fois car c'est ce que la norme C ++ exige. La façon dont cela se produit dépend entièrement des fournisseurs de compilateurs. D'après mon expérience, un indicateur local caché est généré et utilisé par le compilateur.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X