2017-02-13 2 views
5

Ich kenne das Problem der Reihenfolge der Initialisierung von statischen Variablen aus verschiedenen Übersetzungseinheiten. Aber mein Problem ist, innerhalb einer Übersetzungseinheit und in der Tat innerhalb einer Struktur:Wie kommt es, dass die Definitionsreihenfolge bei der Definition statischer Membervariablen nicht eingehalten wird?

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; 
} 

Die Ausgabe lautet:

Entered computeAllMDDeltas 
Exiting computeAllMDDeltas 
computeAllActions 

Zu meiner Überraschung wird computeAllMDDeltas vor computeAllActions genannt und so allActions_ ist nicht initialisiert, wenn es in computeAllMDDeltas verwendet wird. Interessanterweise wird computeAllActions nicht aufgerufen, selbst wenn allActions_ in computeAllMDDeltas verwendet wird.

Warum passiert das und was ist der empfohlene Weg in dieser Situation?

+1

Das Bit, wo 'computerAllMDDeltas' verwendet' allActions_' ist eindeutig nicht irrelevant - aber Sie haben es immer noch entfernt. Bitte gib uns einen [mcve] - das wird ein bisschen Arbeit für dich sein, aber da du die Person bist, die das Problem hat, scheint das vernünftig. –

+0

Sind Sie * sicher * 'computeAllMDDeltas' verwendet' allActions_'? Können Sie den Code aktualisieren, um eine Vorstellung von der Verwendung zu geben? –

+2

Beachten Sie, dass die Definitionen von 'allActions_' und' mdDeltas_' Definitionen von ** templates ** sind, nicht Definitionen von Objekten. 'SlidingTile <2, 3> :: allActions_' und' SlidingTile <2, 3> :: mdDeltas_' haben keine expliziten Definitionen. –

Antwort

5

Wie kommt es, dass die Definitionsreihenfolge nicht eingehalten wird, wenn statische Elementvariablen definiert werden?

Da der Standard sagt, dass die Initialisierung ungeordnete ist:

[basic.start.init]/2 (N4140 Standardentwurf)

... Definitionen explizit spezialisierten Klassen-Template statisch Datenmitglieder haben die Initialisierung bestellt. Andere statische Datenelemente der Klassenvorlage (d. H. Implizit oder explizit instanziierte Spezialisierungen) haben Initialisierung. ...


was ist die empfohlene Art und Weise in dieser Situation?

Gleiche wie Initialisierung über Übersetzungseinheiten: Construct Bei der ersten Verwendung Idiom:

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

Bin ich richtig in der Annahme, dass, sobald die Aufrufe dieser Funktionen inline sind, es keinen Overhead gibt, der mit der Verwendung dieser Technik verbunden ist? – AlwaysLearning

+0

@AlwaysLearning gibt es ein wenig Aufwand, wenn das Programm mit Multi-Threading-Unterstützung kompiliert wird. Die Initialisierung muss synchronisiert werden, um eine Race-Bedingung zu verhindern, die auftreten kann, wenn mehrere Threads die Funktion gleichzeitig aufrufen. – user2079303

+0

Wollten Sie auch 'static const' verwenden (d. H. Wurde' static' versehentlich ausgelassen?), Um zu verhindern, dass diese Variablen jedes Mal neu berechnet werden, wenn die entsprechenden Funktionen aufgerufen werden? – AlwaysLearning

Verwandte Themen