2009-09-14 15 views
53

Es scheint keine einfache Antwort darauf zu geben, aber gibt es irgendwelche Annahmen, die sicher getroffen werden können, wenn auf ein statisches Klassenfeld zugegriffen werden kann?Wann werden statische C++ - Klassenmitglieder initialisiert?

EDIT: Die einzige sichere Annahme scheint zu sein, dass alle Statik initialisiert wird, bevor das Programm beginnt (Aufruf an main). Also, solange ich die Statik nicht von einem anderen statischen Initialisierungscode referenziere, sollte ich mir keine Sorgen machen müssen.

+2

macht mich froh, dass ich .net Entwicklung jetzt, wo die Antwort ist "kurz bevor Sie sie verwenden". – Massif

+0

Ich würde Ihrer Schlussfolgerung in der Bearbeitung zustimmen. Die einzige Art der Verarbeitung, die gleichzeitig mit der statischen Initialisierung erfolgt, ist eine andere statische Initialisierung. (Natürlich kann das mit anderen Sachen zusammenpassen, die die Implementierung tut, aber nichts, was du schreibst.) –

+5

Wenn du diese Karte spielen willst, dasselbe in C++, außer dass wir nur bezahlen, wenn wir es brauchen. : P – GManNickG

Antwort

47

Der Standard garantiert zwei Dinge - dass Objekte in der gleichen Übersetzungseinheit definiert sind (normalerweise bedeutet es.CPP-Datei) werden in der Reihenfolge ihrer Definitionen initialisiert (Erklärungen nicht):

3.6.2

Der Speicher für Objekte mit statischer Speicherdauer (basic.stc.static) beträgt Null initialisiert (dcl.init) bevor irgendeine andere Initialisierung stattfindet. Zero-Initialisierung und Initialisierung mit einem konstanten Ausdruck werden zusammen statische Initialisierung genannt; Alle anderen Initialisierungen sind dynamische Initialisierungen. Objekte von POD-Typen (basic.types) mit statischer Speicherdauer, die mit konstanten Ausdrücken (expr.const) initialisiert sind, müssen initialisiert werden, bevor eine dynamische Initialisierung stattfindet. Objekte mit statischer Speicherdauer, die im Namensraumbereich in der gleichen Übersetzungseinheit definiert und dynamisch initialisiert sind, werden in der Reihenfolge initialisiert, in der ihre Definition in der Übersetzungseinheit erscheint.

Die andere garantiert ist, dass die Initialisierung von statischen Objekten aus einer Übersetzungseinheit wird vor der Verwendung einer beliebigen Objekts oder eine Funktion von dieser Übersetzungseinheit erfolgen:

Es ist die Implementierung definiert, ob die Die dynamische Initialisierung (dcl.init, class.static, class.ctor, class.expl.init) eines Objekts des Namespacebereichs erfolgt vor der ersten Anweisung von main. Wenn die Initialisierung auf einen Zeitpunkt nach der ersten Anweisung von main verschoben wird, soll sie vor der ersten Verwendung einer Funktion oder eines Objekts erfolgen, die in der gleichen Übersetzungseinheit definiert sind wie das zu initialisierende Objekt.

Nichts anderes ich garantiert (insbesondere Reihenfolge der Initialisierung von Objekten in verschiedenen Übersetzungseinheiten definiert ist Implementierung definiert).

BEARBEITEN Wie in Sumas Kommentar gezeigt, ist es auch garantiert, dass sie initialisiert werden, bevor main eingegeben wird.

+8

Ich denke, es gibt eine weitere Sache garantiert, "Sie werden initialisiert, bevor das Programm startet (d. H. Bevor main eingegeben wird)" - das sollte in dieser Antwort enthalten sein, denke ich. – Suma

+0

Was ist, wenn ich eine Binärdatei habe, die eine 'main()' Funktion hat und statisch Teil einer Bibliothek ist, die dynamisch mit Binär verknüpft ist? Statisch initialisiert, bevor main aufgerufen wird? – Dilawar

+2

Es gibt jetzt einen Widerspruch in der obigen Antwort, aufgrund der EDIT. Das zweite gelbe Kästchen (Zitat des Standards) sagt: "Wenn die Initialisierung auf einen Zeitpunkt nach der ersten Anweisung von main() ... verschoben wird, und Sie hinzugefügt haben" garantiert passieren vor main() ", was dem widerspricht, und zitiert nicht den Standard. –

1

Ich glaube, es kann jederzeit während der Ausführung zugegriffen werden. Was nicht definiert ist, ist die Initialisierungsreihenfolge der statischen Variablen.

0

Es gibt keine völlig triviale Antwort auf diese Frage, aber im Grunde werden sie initialisiert, kurz bevor die Kontrolle an den Eingangspunkt (main) Ihres Programms übergeben wird. Die Reihenfolge, in der sie initialisiert werden, ist (meines Wissens) undefiniert und kann compilerspezifisch sein.

EDIT: Um zu verdeutlichen, ist Ihre zusätzliche Annahme richtig. Solange Sie nur nach dem Haupteintrag darauf zugreifen, müssen Sie sich nicht wirklich darum kümmern, wann/wie es initialisiert wird. Es wird zu dieser Zeit initialisiert werden.

1

Sie können in einer Implementierungsdatei (.c/cpp/cc) initialisiert werden. Initialisieren Sie sie nicht in .h, da sich der Compiler über mehrere Definitionen beschweren wird.

Sie werden in der Regel vor der Hauptversion initialisiert, die Reihenfolge ist jedoch unbekannt, daher werden Abhängigkeiten vermieden. Sie können sicherlich innerhalb der Mitgliedsfunktion aufgerufen werden. Beachten Sie, dass die Reihenfolge der Initialisierung für statische Mitglieder unbekannt ist. Ich würde vorschlagen, ein statisches Mitglied in die statische Funktion einzukapseln, die prüft, ob das Mitglied initialisiert worden ist.

17

Sie werden initialisiert, bevor das Programm startet (d. H. Bevor main eingegeben wird).

Wenn zwei oder mehr Definitionen (von statischen Daten) in einer einzelnen CPP-Datei vorhanden sind, werden sie in der Reihenfolge initialisiert, in der sie in der Datei definiert sind (die in der Datei definierte/höhere) initialisiert vor dem nächsten ist).

Wenn zwei oder mehr Definitionen (von statischen Daten) in mehr als einer CPP-Datei vorhanden sind, ist die Reihenfolge, in der die CPP-Dateien verarbeitet werden, nicht definiert/implementierungsspezifisch. Dies ist ein Problem, wenn der Konstruktor einer globalen Variablen (die vor dem Start des Programms aufgerufen wurde) auf eine andere globale Variable verweist, die in einer anderen CPP-Datei definiert ist, die möglicherweise noch nicht erstellt wurde. Allerdings Artikel 47 von Effective C Meyers ++ (die den Titel Stellen Sie sicher, dass die globale Objekte initialisiert werden, bevor sie gewohnt sind) nicht beschreibt ein Work-around ...

  • Definieren Sie eine statische Variable in eine Header-Datei (es ist statisch, so dass Sie mehrere Instanzen ohne den Linker beschwert haben kann)

  • haben Sie den Konstruktor dieser variablen invoke was auch immer Sie es brauchen (insbesondere die globalen Singletons in den Headern deklariert konstruieren)

... was es sagt, ist eine Technik, die in einigen System-Header-Dateien, z.B. um sicherzustellen, dass die globale Variable cin initialisiert wird, bevor sie selbst von den Konstruktoren der statischen Variablen verwendet wird.

+2

In der Effektiven C++ 3. Ausgabe ist Punkt 4: Stellen Sie sicher, dass Objekte initialisiert werden, bevor sie verwendet werden. (und dort spricht er von nicht-lokalen statischen Variablen zB statische Klassenmitglieder) –

+1

Nicht alle statischen Objekte werden garantiert initialisiert, bevor 'main' eingegeben wird. Siehe Tadeusz Kopecs Antwort auf diese Frage, die den Standard zitiert: "Es ist implementation-definierte, ob die dynamische Initialisierung (dcl.init, class.static, class.ctor, class.expl.init) eines Objekts des Namespace scope ist vor der ersten Aussage von main gemacht. " –

-1

glaube ich der Haupt-Thread eines Proccess werden die folgenden fünf Schritte, um

  1. Initialisierung der CRT-Bibliothek

  2. statische Initialisierung

  3. Ausführung von main() Funktion ausführen

  4. statische Einheitlichkeit

  5. unitialization der CRT-Bibliothek

Sie wollen Referenz Statik aus anderen statischen Initialisierungscode? vielleicht die folgenden Codes funktionieren:

class A; 
static auto_ptr<A> a(auto_ptr<A>(&GetStaticA())); 
A &GetStaticA(void) 
{ 
    static A *a = NULL; //the static basic type variables initialized with constant experession will be initialized earlier than the other static ones 
    if (a == NULL) 
    { 
     a = new A(); 
     return *a; 
    } 
} 
3

Ihre endgültige Entscheidung im Edit korrekt ist. Aber das Problem ist die Klasse selbst statisch. Es ist einfacher zu sagen, dass mein Code statische Member haben wird, die nicht auf andere statische Mitglieder der globalen Daten/Klasse verweisen, aber sobald Sie diesen Weg gehen, werden die Dinge bald schiefgehen. Ein Ansatz, den ich in der Praxis als nützlich empfunden habe, sind keine statischen Datenelemente der Klasse, sondern statische Wrappermethoden der Klasse. Diese Methoden können dann das statische Objekt in sich halten. Für z.B.

TypeX* Class2::getClass1Instance() 
{ 
    static TypeX obj1; 
    return &obj1; 
} 

Hinweis: Eine frühere Antwort sagt:

Die andere garantierte Sache, dass die Initialisierung von statischen Objekten von einer Übersetzungseinheit vor der Verwendung eines beliebigen Objekts oder Funktion von dieser Übersetzungseinheit wird geschehen ist

Dies ist nicht vollständig korrekt und der Standard wird hier falsch abgeleitet. Dies trifft möglicherweise nicht zu, wenn die Funktion von einer Übersetzungseinheit aufgerufen wird, bevor main eingegeben wird.

Verwandte Themen