2017-02-13 1 views
5

Je connais le problème de l'ordre d'initialisation des variables statiques de différentes unités de traduction. Cependant, mon problème est dans une unité de traduction et, en fait, dans un struct:Pourquoi l'ordre de définition n'est pas suivi lors de la définition de variables membres statiques?

template <int size> 
struct SlidingTile { 
    using AllActions = std::array<int, size>; 
    using AllMDDeltas = std::array<int, size>; 

    int mdDelta(int i) const { 
     return mdDeltas_[i]; 
    } 

    static AllActions computeAllActions() { 
     std::cout << "computeAllActions" << std::endl; 
     AllActions res; 
     for (int i = 0; i < size; ++i) res[i] = i; 
     return res; 
    } 

    static AllMDDeltas computeAllMDDeltas() { 
     std::cout << "Entered computeAllMDDeltas" << std::endl; 
     AllActions res; 
     for (int i = 0; i < size; ++i) res[i] = 10 * allActions_[i]; 
     std::cout << "Exiting computeAllMDDeltas" << std::endl; 
     return res; 
    } 

private: 
    static const AllActions allActions_; 
    static const AllMDDeltas mdDeltas_; 
}; 

template <int size> 
const typename SlidingTile<size>::AllActions 
    SlidingTile<size>::allActions_ = SlidingTile<size>::computeAllActions(); 

template <int size> 
const typename SlidingTile<size>::AllMDDeltas 
    SlidingTile<size>::mdDeltas_ = SlidingTile<size>::computeAllMDDeltas(); 

int main() { 
    SlidingTile<3> s; 
    std::cout << s.mdDelta(2) << std::endl; 
    return 0; 
} 

La sortie est:

Entered computeAllMDDeltas 
Exiting computeAllMDDeltas 
computeAllActions 

À ma grande surprise, computeAllMDDeltas est appelé avant computeAllActions et ainsi allActions_ n'est pas initialisé lorsqu'il est utilisé dans computeAllMDDeltas. Fait intéressant, computeAllActions n'est pas appelé même lorsque allActions_ est utilisé dans computeAllMDDeltas.

Pourquoi cela se produit-il et quelle est la manière conseillée dans cette situation?

+1

Le bit où 'computerAllMDDeltas' utilise' allActions_' est manifestement pas hors de propos - mais vous avez encore enlevé. S'il vous plaît donnez-nous un [mcve] - ce sera un peu de travail pour vous, mais comme vous êtes la personne qui a le problème, cela semble raisonnable. –

+0

Êtes-vous * certain * 'computeAllMDDeltas' utilise' allActions_'? Pouvez-vous mettre à jour le code pour donner une idée de l'utilisation. –

+2

Notez que les définitions de 'allActions_' et' mdDeltas_' sont des définitions de ** templates **, pas des définitions d'objets. 'SlidingTile <2, 3> :: allActions_' et' SlidingTile <2, 3> :: mdDeltas_' n'ont pas de définitions explicites. –

Répondre

5

Pourquoi l'ordre de définition n'est pas suivi lors de la définition de variables membres statiques?

Parce que la norme indique que l'initialisation est non ordonnée:

[basic.start.init]/2 (projet de norme N4140)

... Définitions du modèle de classe explicitement spécialisé statique les membres de données ont commandé l'initialisation. D'autres membres de données statiques de modèle de classe (c'est-à-dire, des spécialisations implicitement ou explicitement instanciées) ont initialisation . ...


Quelle est la façon conseillé dans cette situation?

Identique à l'initialisation dans toutes les unités de traduction: Construct sur la première utilisation langage:

struct SlidingTile { 
    // ... 
private: 
    static const AllActions& allActions() { 
     static const AllActions instance = computeAllActions(); 
     return instance; 
    } 
    static const AllMDDeltas& mdDeltas() { 
     static const AllMDDeltas instance = computeAllMDDeltas(); 
     return instance; 
    } 
}; 
+0

Ai-je raison de penser que, une fois que les appels à ces fonctions sont en ligne, il n'y a aucun surcoût impliqué dans l'utilisation de cette technique? – AlwaysLearning

+0

@AlwaysLearning il y a un peu de surcharge si le programme est compilé avec le support multi-threading. L'initialisation doit être synchronisée pour empêcher une condition de concurrence qui pourrait se produire si plusieurs threads appellent la fonction simultanément. – user2079303

+0

Également, vouliez-vous utiliser 'static const' (c'est-à-dire' static' est-il omis par erreur?) Pour éviter de re-calculer ces variables chaque fois que les fonctions correspondantes sont appelées? – AlwaysLearning