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 ça se passe? Est-ce que cela se traduit par une sorte de tordu si la déclaration? (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 ) ; } 

Oui, cela se traduit normalement par une instruction if implicite avec un indicateur booléen interne. Ainsi, dans la mise en œuvre la plus élémentaire, 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; } ... } 

De plus, si votre object statique a un destructeur non sortingvial, le langage doit obéir à une autre règle: ces objects statiques doivent être détruits dans l’ordre inverse de leur construction. Étant donné que l’ordre de construction n’est connu qu’à l’exécution, l’ordre de destruction est également défini lors de l’exécution. Ainsi, chaque fois que vous construisez un object statique local avec un destructeur non sortingvial, le programme doit l’enregistrer dans une sorte de conteneur linéaire, qu’il utilisera ultérieurement pour détruire ces objects dans le bon ordre.

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


Il est utile d’append que lorsqu’il s’agit d’objects statiques de types “primitifs” (comme int dans votre exemple) initialisés avec des constantes de compilation, le compilateur est libre d’initialiser cet object au démarrage. Vous ne remarquerez jamais la différence. Cependant, si vous prenez un exemple plus compliqué avec un object “non primitif”

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

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

Dans votre cas, l’initialiseur n’est pas connu à la compilation, ce qui signifie que le compilateur doit retarder l’initialisation et l’utiliser implicitement if .

Oui, le compilateur génère généralement un booléen caché “at-il été initialisé?” flag et un if qui s’exécute chaque fois que la fonction est exécutée.

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

Bien que ce soit en effet “une sorte de tordu si”, la torsion peut être plus que ce que vous aviez imaginé …

Le commentaire de ZoogieZork sur la réponse d’AndreyT touche un aspect important: l’ initialisation des variables locales statiques – sur certains compilateurs, y compris GCC – est par défaut sûre (une option de ligne de commande du compilateur peut la désactiver). Par conséquent, il utilise un mécanisme de synchronisation inter-thread (une opération de mutex ou atomique quelconque) qui peut être relativement lente . Si vous ne vous sentez pas à l’aise – en termes de performances – avec l’utilisation explicite d’une telle opération dans votre fonction, vous devriez alors envisager une alternative moins impactante à l’initialisation paresseuse de la variable (la construire explicitement de manière threadsafe) quelque part juste une fois). Très peu de fonctions sont si sensibles à la performance que cela importe – ne laissez pas cela gâcher votre journée ou rendre votre code plus compliqué, à moins que vos programmes ne soient trop lents et que votre profileur ne touche cette zone.

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