Question

Lorsque j'utilise des variables statiques en C ++, je finis souvent par vouloir initialiser une variable en transmettant une autre à son constructeur. En d'autres termes, je souhaite créer des instances statiques dépendantes les unes des autres.

Dans un seul fichier .cpp ou .h, le problème ne se pose pas: les instances sont créées dans l'ordre dans lequel elles sont déclarées. Toutefois, lorsque vous souhaitez initialiser une instance statique avec une instance dans une autre unité de compilation, l'ordre semble impossible à spécifier. Le résultat est que, en fonction de la météo, il peut arriver que l'instance qui dépend d'une autre soit construite, et ce n'est qu'après que l'autre instance est construite. Le résultat est que la première instance est incorrectement initialisée.

Quelqu'un sait-il comment s'assurer que les objets statiques sont créés dans le bon ordre? J'ai longtemps cherché une solution, en essayant toutes les solutions (y compris la solution Schwarz Counter), mais je commence à douter qu'il en existe une qui fonctionne vraiment.

Une astuce consiste à manipuler le membre de fonction statique:

Type& globalObject()
{
    static Type theOneAndOnlyInstance;
    return theOneAndOnlyInstance;
}

En effet, cela fonctionne. Malheureusement, vous devez écrire à globalObject (). MemberFunction () au lieu de globalObject.MemberFunction (), ce qui entraîne un code client quelque peu déroutant et inélégant.

Mise à jour: Merci pour vos réactions. Malheureusement, il semble en effet que j'ai répondu à ma propre question. Je suppose que je devrai apprendre à vivre avec ça ...

Était-ce utile?

La solution

Vous avez répondu à votre propre question. L'ordre d'initialisation statique n'est pas défini et la manière la plus élégante de le contourner (tout en continuant l'initialisation statique, c'est-à-dire de ne pas le refactoriser complètement) consiste à envelopper l'initialisation dans une fonction.

Lisez les éléments de la FAQ C ++ à partir de https://isocpp.org/wiki / faq / ctors # static-init-order

Autres conseils

Peut-être devriez-vous vous demander si vous avez besoin d'autant de variables statiques globales. Bien qu’elles puissent parfois être utiles, il est souvent beaucoup plus simple de les reformuler dans une portée locale plus petite, en particulier si vous constatez que certaines variables statiques dépendent d’autres.

Mais vous avez raison, il n’ya aucun moyen de garantir un ordre d’initialisation particulier. Par conséquent, si l’on tient à cœur, conserver l’initialisation dans une fonction, comme vous l’avez mentionné, est probablement le moyen le plus simple.

  

En effet, cela fonctionne. Malheureusement, vous devez écrire à globalObject (). MemberFunction () au lieu de globalObject.MemberFunction (), ce qui entraîne un code client quelque peu déroutant et inélégant.

Mais le plus important, c’est que cela fonctionne et qu’il soit à l’abri des erreurs, c.-à-d. il n'est pas facile de contourner le bon usage.

L’exactitude du programme doit être votre première priorité. En outre, à mon humble avis, le () ci-dessus est purement stylistique - c'est-à-dire. complètement sans importance.

En fonction de votre plate-forme, faites attention à une initialisation trop dynamique. Le nombre de tâches de nettoyage pouvant être initialisées pour les initialiseurs dynamiques est relativement faible (voir ici ). Vous pouvez résoudre ce problème en utilisant un conteneur d'objets globaux contenant des membres différents objets globaux. Vous avez donc:

Globals & getGlobals ()
{
  static Globals cache;
  return cache;
}

Un seul appel à ~ Globals () permet de nettoyer tous les objets globaux de votre programme. Pour accéder à un réseau global, vous avez encore quelque chose comme:

getGlobals().configuration.memberFunction ();

Si vous le souhaitez vraiment, vous pouvez le placer dans une macro pour enregistrer un petit peu de frappe à l'aide d'une macro:

#define GLOBAL(X) getGlobals().#X
GLOBAL(object).memberFunction ();

Bien qu'il ne s'agisse que du sucre syntaxique dans votre solution initiale.

Le fait d’envelopper la statique dans une méthode résoudra le problème de l’ordre, mais il n’est pas thread-safe, comme d’autres l'ont déjà souligné, mais vous pouvez le faire également pour en faire un thread si cela pose un problème.

// File scope static pointer is thread safe and is initialized first.
static Type * theOneAndOnlyInstance = 0;

Type& globalObject()
{
    if(theOneAndOnlyInstance == 0)
    {
         // Put mutex lock here for thread safety
         theOneAndOnlyInstance = new Type();
    }

    return *theOneAndOnlyInstance;
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top