Question

Si une variable est déclarée comme statique dans l'étendue d'une fonction, elle n'est initialisée qu'une fois et conserve sa valeur entre les appels de fonction. Quelle est exactement sa durée de vie? Quand appelle-t-on son constructeur et son destructeur?

void foo() 
{ 
    static string plonk = "When will I die?";
}
Était-ce utile?

La solution

La durée de vie des variables de fonction static commence la première fois que [0] le flux de programme rencontre la déclaration et se termine à la fin du programme. Cela signifie que le temps d'exécution doit effectuer une certaine comptabilité afin de le détruire uniquement s'il a été construit.

De plus, étant donné que la norme indique que les destructeurs d'objets statiques doivent s'exécuter dans l'ordre inverse de l'achèvement de leur construction [1] , l'ordre de construction peut dépendre de l'exécution du programme spécifique. , l'ordre de construction doit être pris en compte.

Exemple

struct emitter {
    string str;
    emitter(const string& s) : str(s) { cout << "Created " << str << endl; }
    ~emitter() { cout << "Destroyed " << str << endl; }
};

void foo(bool skip_first) 
{
    if (!skip_first)
        static emitter a("in if");
    static emitter b("in foo");
}

int main(int argc, char*[])
{
    foo(argc != 2);
    if (argc == 3)
        foo(false);
}

Résultat:

  

C: > sample.exe
  Créé dans foo
  Détruit dans foo

     

C: > sample.exe 1
  Créé en si
  Créé dans foo
  Détruit dans foo
  Détruit dans si

     

C: > sample.exe 1 2
  Créé dans foo
  Créé en si
  Détruit dans si
  Détruit dans foo

[0] Etant donné que C ++ 98 [2] ne contient aucune référence à plusieurs threads, son comportement dans une multi- L’environnement threadé n’est pas spécifié et peut poser problème car Roddy mentionne.

[1] C ++ 98 section 3.6.3.1 [basic.start.term]

[2] En C ++ 11, les statiques sont initialisées de manière sécurisée pour les threads. Cette action est également appelée Statique magique .

Autres conseils

Motti a raison en ce qui concerne l'ordre, mais il y a d'autres éléments à prendre en compte:

Les compilateurs utilisent généralement une variable d'indicateur caché pour indiquer si la statique locale a déjà été initialisée et cet indicateur est vérifié à chaque entrée de la fonction. Évidemment, il s’agit là d’une petite perte de performances, mais le problème, c’est que ce drapeau n’est pas garanti comme étant thread-safe.

Si vous avez une statique locale comme ci-dessus et que foo est appelé à partir de plusieurs threads, vous pouvez avoir des conditions de concurrence entraînant l'initialisation incorrecte de plonk , voire plusieurs fois. De plus, dans ce cas, plonk peut être détruit par un thread différent de celui qui l'a construit.

Malgré ce que dit la norme, je me méfierais beaucoup de l'ordre de destruction statique local, car il est possible que vous dépendiez involontairement d'un caractère statique toujours valide après sa destruction, ce qui est très difficile à suivre. vers le bas.

Les explications existantes ne sont pas complètes sans la règle actuelle de la norme, trouvée dans 6.7:

  

L’initialisation à zéro de toutes les variables de portée de bloc avec une durée de stockage statique ou une durée de stockage de thread est effectuée avant toute autre initialisation. L'initialisation constante d'une entité de portée de bloc avec une durée de stockage statique, le cas échéant, est effectuée avant la première entrée de son bloc. Une implémentation est autorisée à effectuer une initialisation précoce d'autres variables de portée de bloc avec une durée de stockage statique ou d'unités d'exécution dans les mêmes conditions qu'une implémentation est autorisée à initialiser de manière statique une variable avec une durée de stockage statique ou d'une durée d'exécution dans l'étendue de l'espace de noms. Sinon, une telle variable est initialisée la première fois que le contrôle passe par sa déclaration; une telle variable est considérée comme initialisée à la fin de son initialisation. Si l'initialisation se termine par une exception, l'initialisation   n’est pas terminé, il sera réessayé la prochaine fois que le contrôle entrera dans la déclaration. Si le contrôle entre la déclaration simultanément alors que la variable est en cours d'initialisation, l'exécution simultanée doit attendre la fin de l'initialisation. Si le contrôle ré-entre la déclaration de manière récursive pendant l’initialisation de la variable, le comportement est indéfini.

FWIW, Codegear C ++ Builder ne se détruit pas dans l'ordre attendu conformément à la norme.

C:\> sample.exe 1 2
Created in foo
Created in if
Destroyed in foo
Destroyed in if

... ce qui est une autre raison de ne pas compter sur l'ordre de destruction!

Les variables statiques entrent en jeu une fois que l'exécution du programme commence et restent disponibles jusqu'à la fin de l'exécution du programme.

Les variables statiques sont créées dans le segment de données de la mémoire .

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top