4

Il existe un modèle simple et bien connu pour éviter le fiasco d'initialisation statique, décrit dans section 10.13 of the C++ FAQ Lite. Il y a un compromis à faire dans le fait que l'objet construit n'est jamais détruit (ce qui n'est pas un problème si le destructeur n'a pas d'effets secondaires importants) ou que l'objet statique n'est pas accessible depuis le destructeur d'un autre objet statique (voir section 10.14 of the C++ FAQ Lite).Comment effectuer une dés-initialisation statique si le destructeur a des effets secondaires et que l'objet est accédé à partir du destructeur d'un autre objet statique?

Alors ma question est la suivante: Comment peut-on éviter le fiasco statique de-initialisation si un destructeur de l'objet statique a des effets secondaires importants qui doivent éventuellement se produire et l'objet statique doit être accédées par le destructor d'un autre objet statique?


(Note: la FAQ-lite mentionne cette question reçoit une réponse FAQ 16,17 de C++ FAQ:. Foire aux questions par M. Cline et G. et Lomow je n'ai pas accès à ce livre, ce qui explique pourquoi je pose cette question à la place.)

+4

Voir ici: http://stackoverflow.com/questions/335369/finding-c-static-initialization-order-problems/335746#335746 –

+0

Merci, c'est le point que je manquais ... – Tobias

+0

C++ FAQ Lite déplacé à http://www.dietmar-kuehl.de/mirror/C++ - faq/ – shargors

Répondre

4

Les objets statiques fonctionnels comme les objets globaux sont garantis être détruits (en supposant qu'ils sont créés).

L'ordre de destruction est l'inverse de la création.
Ainsi, si un objet dépend d'un autre objet lors de la destruction, vous devez garantir qu'il est toujours disponible. Ceci est relativement simple car vous pouvez forcer l'ordre de destruction en vous assurant que l'ordre de création est fait correctement.

Le lien suivant est sur le point singeltons mais décrit une situation similaire et sa solution:
Finding C++ static initialization order problems

extrapolant au cas général de GLOBALS initialisés paresseux comme décrit dans la FAQ Lite nous pouvons résoudre le problème comme celui-ci:

namespace B 
{ 
    class B { ... }; 

    B& getInstance_Bglob; 
    { 
     static B instance_Bglob; 
     return instance_Bglob;; 
    } 

    B::~B() 
    { 
     A::getInstance_abc().doSomthing(); 
     // The object abc is accessed from the destructor. 
     // Potential problem. 
     // You must guarantee that abc is destroyed after this object. 
     // To gurantee this you must make sure it is constructed first. 
     // To do this just access the object from the constructor. 
    } 

    B::B() 
    { 
     A::getInstance_abc(); 
     // abc is now fully constructed. 
     // This means it was constructed before this object. 
     // This means it will be destroyed after this object. 
     // This means it is safe to use from the destructor. 
    } 
} 
namespace A 
{ 
    class A { ... }; 

    A& getInstance_abc() 
    { 
     static A instance_abc; 
     return instance_abc; 
    } 
} 
+0

L'un des correctifs de C++ 0x est l'ordre de destruction déterministe des variables statiques locales de la fonction.Donc en C++ 03, vous n'avez aucune garantie que A sera détruit après B même si A a été construit avant B. La seule exception notable est quand A et B sont définis dans la même unité de compilation. –

+1

@Caspin: Dans la norme actuelle "ISO/IEC 14882" (http://openassist.googlecode.com/files/C%2B%2B%20Standard%20-%20ANSI%20ISO%20IEC%2014882%202003.pdf) c'est bien défini. See section "3.6.3 Termination" Paragraphe 1: Destructeurs (12.4) pour les objets initialisés de durée de stockage statique (déclarés à la portée de bloc ou à l'espace de noms portée) sont appelés suite à un retour de principal et à l'issue de l'appel de sortie (18.3). Ces objets sont détruits dans l'ordre inverse de l'achèvement de leur constructeur ou de l'achèvement de leur initialisation dynamique .

+0

On dirait que vous avez raison. L'ordre de destruction est toujours l'ordre de construction inverse. J'étais sous l'impression que C++ seulement garanti dans une unité de compilation, pas tout le programme. Je devrais lire la spécification plus souvent. Mon commentaire à propos de C++ 0x a été de me tromper sur le nouvel ordre de destruction multithread introduit avec le nouveau standard. –

0

Tant que le destructeur statique de l'autre objet s'exécute en premier, tout va bien. Vous pouvez assurer cela en faisant construire l'autre objet avant "l'objet A". Tant que les deux objets sont déclarés dans la même unité de compilation, ils sont initialisés dans l'ordre dans lequel ils apparaissent dans la source et détruits dans l'ordre inverse.

Si vous avez besoin que cela se produise entre plusieurs unités de compilation, vous n'avez pas de chance. Il est préférable de les créer dynamiquement au moment de l'exécution et de les détruire à la fin de la partie principale, plutôt que de les rendre statiques.

+0

L'OP cite spécifiquement un lien vers un motif qui évite la nécessité que les globals soient dans la même unité de compilation. En utilisant la même technique, il peut obtenir un ordre de construction défini et donc un ordre de destruction défini, donc il n'a pas de chance. –

0

C'est un peu un hack mais j'ajouterais des boolos statiques pour garder une trace de l'ordre de initialisation Puis l'objet qui finit le dernier fait le nettoyage même s'il n'est pas le propriétaire.