Konstruktionsreihenfolge
-
Ich weiß, dass die Konstruktionsreihenfolge globaler Objekte laut Standard undefiniert ist. Wie sieht es aber mit der Initialisierung fundamentaler Typen aus?
class Foo { public : Foo() { ++numFoos; } ~Foo() { --numFoos; } static unsigned int numFoos; }; unsigned int Foo::numFoos = 0; Foo fooA, fooB, fooC; int main() { [...] }Meiner Erfahrung nach kann es hier nicht passieren, dass numFoos an irgendeiner Stelle zwischen Konstruktion und Zerstörung der Foo-Objekte einen undefinierten Wert enthält. Ist diese Annahme richtig? Und wenn ja, warum?
Was wäre, wenn der Typ von numFoos zu MyNumberClass geändert würde? Man hätte sich dann einigermaßen subtil in den Fuß geschossen, oder? Denn die Konstruktion von numFoos könnte ja erst nach den Foo-Objekten erfolgen, bzw. die Destruktion schon vorher.
Sollte man deshalb prinzipiell davon absehen, im Konstruktor/Destruktor auf statische Member zuzugreifen? Oder wäre das übers Ziel hinausgeschossen?
-
pock schrieb:
Ich weiß, dass die Konstruktionsreihenfolge globaler Objekte laut Standard undefiniert ist.
Das gilt allerdings nur über mehrere Übersetzungseinheiten hinweg. Innerhalb einer ÜE ist die Reihenfolge sehr wohl definiert.
Meiner Erfahrung nach kann es hier nicht passieren, dass numFoos an irgendeiner Stelle zwischen Konstruktion und Zerstörung der Foo-Objekte einen undefinierten Wert enthält. Ist diese Annahme richtig? Und wenn ja, warum?
Primitive Datentypen werden statisch initialisiert und sind somit garantiert initialisiert bevor irgendein Konstruktor aufgerufen wird.
Was wäre, wenn der Typ von numFoos zu MyNumberClass geändert würde?
In deinem Beispiel wäre es kein Problem, da die Konstruktionsreihenfolge innerhalb einer ÜE definiert ist. numFoos würde nach wie vor den Foos initialisiert werden, da es vor den Foos definiert wurde.
Sollte man deshalb prinzipiell davon absehen, im Konstruktor/Destruktor auf statische Member zuzugreifen? Oder wäre das übers Ziel hinausgeschossen?
Wie immer gilt: man sollte wissen was man tut. Wirklich problematisch wird es nur mit globalen Objekten aus anderen ÜEs.
-
Innerhalb einer Übersetzungseinheit werden globale Objekte von oben nach unten abgearbeitet. Das heißt, wenn du wie hier alles in einer Datei zusammengefasst hast, sollte es keine Probleme geben. Aber sobald du die Implementation der Klasse Foo in eine eigene ÜE auslagerst, kannst du Probleme mit der Initialisierungsreihenfolge bekommen.
-
Ah ok, da war mein Beispiel zu kurz gedacht. Ich meinte den ungünstigsten Fall, also über verschiedene ÜE hinweg.
Danke euch beiden.