2010-01-29 5 views
3

J'ai une classe (A) qui accède (indirectement via une méthode statique) à une variable statique (un conteneur STL) dans une autre classe (B) dans son constructeur et son destructeur. Un objet peut être global, des constantes globales, des membres statiques d'une autre classe, stockés dans d'autres classes (qui peuvent eux-mêmes avoir des instances globales ou statiques) ou, fondamentalement, n'importe où ailleurs, un objet C++ peut l'être.C++ Contrôle de l'ordre des destructeurs pour les objets globaux

Si un objet A est construit avant les membres statiques dans B ou détruit après les membres statiques dans B, il provoquera un plantage à un moment donné (généralement une violation d'accès). Existe-t-il un moyen de garantir que toutes les instances de la classe A (à l'exception de celles qui ont fui, étant par définition "perdues" et donc non détruites) sont construites après et détruites avant la variable statique de B?

J'ai vu quelques solutions pour faire une variable spécifique être construit/détruit avant/après un autre, mais pas un cas général de toutes les instances d'un type donné alors je ne sais pas comment aborder cela.

Répondre

8

Non. Il s'agit du static-initialization fiasco. L'ordre dans lequel les objets sont construits avant d'entrer dans le champ principal n'est pas spécifié. La seule garantie est que cela arrive.

Ce que vous pouvez faire est paresseux-initialiser. Cela signifie que vos objets ne seront pas initialisés tant que vous ne les utiliserez pas. Tels que:

struct A { /* some data */ }; 
struct B { B(void){ /* get A's data */ } }; 

A& get_A(void) 
{ 
    static A instance; 
    return instance; 
} 

B& get_B(void) 
{ 
    static B instance; 
    return instance; 
} 

Vous utilisez get_A et get_B pour obtenir les instances mondiales. La partie où B utilise A doit utiliser get_A, et votre utilisation de B doit correspondre à get_B. Notez que le get_B est facultatif dans votre cas. Que se passe-t-il lorsque B est créé pour la première fois?

(Soit globalement ou dans la fonction) Le constructeur appellera get_A et c'estA sera créé. Cela vous permet de contrôler l'ordre dans lequel les choses sont construites.

note Je pense que je renversé votre A et B.

+2

Il demande à propos de la destruction, pas de l'initialisation. –

+4

@Neil: L'ordre de destruction est déterminé par l'ordre d'initialisation. – GManNickG

+0

Donc je peux juste changer mon "conteneur Container statique" à "static Container & getContainer() {statique Conteneur Conteneur; retour conteneur;}" et il serait libéré après tout ce qui directement ou indirectement appelé getContainer dans son constructeur? Que se passe-t-il si une instance de A a été stockée dans un shared_ptr global plus tard dans le programme? –

1

En général, aucune méthode. Il y a des solutions de contournement, cependant. Vous pouvez obtenir un objet avec une portée globale et une durée de vie un peu moins que globale en ayant un pointeur global et en l'initialisant/détruisant dans main/WinMain. En outre, vous placez votre état global à détruire en dernier dans un objet segmenté par ref.

, Voir également REFONTE :)

1

Le livre "Modern C++ Design" couvre cette question bien.

Google Livres contient des analyses d'une grande partie de celui-ci - voir la section 6.5 (page 135) - link.

1

Vous pouvez gérer cela proprement, en mettant des pointeurs sur les objets dans l'espace global, puis en les ajoutant dans l'ordre désiré dans votre main, et en les détruisant dans l'ordre désiré à la fin de la main.

0

Comme d'autres l'ont souligné, il n'existe aucun moyen standard et portable pour résoudre ce problème, en raison du problème Static initialization order fiasco.

Cependant, vous devriez être capable de résoudre votre problème en appliquant un peu de conception, ainsi vous gagnerez un certain degré de contrôle quand (et comment) les objets de A et B sont construits. Jetez un oeil sur les modèles de conception comme le modèle de création Singleton il est considéré dans de nombreux cas (sinon la plupart) comme anti-pattern, malgré qu'il vaille la peine d'apprendre à ce sujet. Regardez aussi Monostate motif qui peut être utilisé comme un peu mieux Singleton. Ces modèles peuvent aider à contrôler la création et la durée de vie des objets, ainsi les éléments sont correctement initialisés avant utilisation.

Généralement, c'est une bonne idée d'éviter les globales - coller à deglobalisation est une bonne idée.

Questions connexes