L’ordre d’initialisation est-il garanti?

J’utilise quelque chose comme les sections de code suivantes pour effectuer une initialisation. Je sais que l’initialisation de p::i_ n’est pas ordonnée. Je crois que h est ordonné. Je devrais donc pouvoir raisonner sur l’ordre dans lequel il a été initialisé. Étant donné que l’en-tête de p est inclus avant la définition de h , existe-t-il une garantie que p::i_ être initialisé avant h ?

 struct helper { template  helper(const T&, int i) { p::i_::push_back(i); } }; static helper h; 

La classe p est définie ci-dessous.

 template  struct p { static std::vector i_; }; template  std::vector p::i_; 

L’ordre d’initialisation des objects avec une durée de stockage statique est indéfini pour toutes les unités de traduction et séquentiel dans chaque unité de traduction.

Dans votre cas particulier, les choses sont plus compliquées, puisqu’un des objects avec stockage statique est un membre statique d’une classe de modèle. Concrètement, cela signifie que chaque unité de traduction accédant au membre p::i_ créera le symbole et appenda le code d’initialisation approprié. Plus tard, l’éditeur de liens choisira l’une des instances et le conservera. Même s’il semble que p::i_ soit défini avant h dans votre unité de traduction, vous ne savez pas quelle instance de p::i_ sera conservée par l’éditeur de liens, et il peut s’agir d’une instance dans un fichier. unité de traduction différente et donc l’ordre n’est pas garanti.

En général, c’est une mauvaise idée d’avoir des objects globaux. Je vous suggérerais d’essayer de redéfinir votre programme sans ces globals.

Les objects de scope globale ou d’espace de noms sont construits de haut en bas au sein d’une unité de traduction. L’ordre de construction du niveau global ou de l’espace de noms entre les différentes unités de traduction n’est pas défini. Le moyen le plus raisonnable de commander l’initialisation entre les unités de traduction consiste à envelopper les objects dans des fonctions d’accessoires appropriées, par exemple:

 template  something& get() { static something values; return value; } 

Notez cependant que cela n’est pas thread-safe en C ++ 03 (car C ++ 03 n’a de toute façon pas de concepts de thread). Il est thread-safe en C ++ 11.

Non, ce n’est pas garanti.

Ce que vous pouvez faire c’est cependant:

 template std::vector& registry() { static std::vector reg; return reg; } ... registry().push_back(i); ... 

Encore mieux, évitez de faire des choses trop intelligentes au démarrage.

Le débogage avant ou après la fin de la main est un véritable cauchemar (et l’OMI n’a même pas été couverte à 100% par la norme). Une simple inscription est peut-être acceptable, mais ne faites jamais rien qui puisse échouer.

Au fil des années, je me suis éloigné de cette approche d’initialisation / d’arrêt explicite et je n’ai jamais regardé en arrière.