Vorschlag für den nächsten C++-Standard: Statische Konstruktoren und Destruktoren
-
Kellerautomat schrieb:
Genau wie bei Klassenmembern: Definitionsreihenfolge.
Ah, dann hast du an etwas anderes gedacht, nämlich an die Definitionsreihenfolge innerhalb einer Übersetzungseinheit. Die ist ja, soweit ich weiß, auch schon festgelegt. Aber es ist nicht festgelegt, in welcher Reihenfolge die Objekte unterschiedlicher Übersetzungseinheiten dran kommen. Siehe static initialization order fiasco. Deswegen sind "static function locals" mit ihrer "lazy initialization" da viel interessanter.
-
Eine Initialisierungsreihenfolge zwischen UE's festzulegen ergibt überhaupt keinen Sinn. UE's sind schließlich unabhängig voneinander.
-
Heißt wenn du get_stream in einem anderen "statischen globalen Konstruktor" aufrufst, ist der Stream u.U. noch gar nicht initialisiert.. (Bei allen anderen Methoden ist das kein Problem.)
-
Na und? Ist doch egal...
-
Kellerautomat schrieb:
Na und? Ist doch egal...
Bis auf dass dein Programm halt wegen einer Access Violation abschmiert.
Aber bis auf diese Kleinigkeit ists egal, ja.
-
Ich verwende sie doch gar nicht vor main(), also wo liegt euer Problem? Gleich mal voreilig beschweren, obwohl man die Verwendung nicht kennt?
-
Kellerautomat schrieb:
Ich verwende sie doch gar nicht vor main(), also wo liegt euer Problem? Gleich mal voreilig beschweren, obwohl man die Verwendung nicht kennt?
Es ging um Übersetzungseinheiten und Initialisierungsreihenfolge. Und nicht ob jetzt ein konkreter Code funktioniert - deine Idee ist Broken By Design. Das ist der Punkt.
-
Tjoah, UB ist eben UB. Ein guter Compiler warnt vor sowas.
-
Kellerautomat schrieb:
Tjoah, UB ist eben UB. Ein guter Compiler warnt vor sowas.
Vor manchen kann auch ein Compiler nicht warnen.
Ganz davon abgesehen können die Auswirkungen recht langwierige Suchen erfordern (Wir hatten in einem Projekt einen solchen Fall, den Fehler haben wir erst Wochen später entdeckt).
-
Das Problem gabs aber auch schon vorher und ist auch nicht das, welches ich durch dieses Feature lösen möchte.
-
Kellerautomat schrieb:
Eine Initialisierungsreihenfolge zwischen UE's festzulegen ergibt überhaupt keinen Sinn. UE's sind schließlich unabhängig voneinander.
"UEs sind unabhängig voneinander" ist die rosarote Theorie. Die weniger rosarote Praxis sieht anders aus.
Daher würde es schon Sinn ergeben.Bloss dass es nicht unbedingt trivial umzusätzen wäre.
-
Kellerautomat schrieb:
Das Problem gabs aber auch schon vorher und ist auch nicht das, welches ich durch dieses Feature lösen möchte.
Wie mein Code zeigt gibt es aber das Feature bereits - du willst nur syntaktischen Zucker. Der wuerde sich mit Makros loesen lassen - dann sieht es auch huebsch aus.
Das Problem aber ist: dass Feature bringt nichts, weil eben die Initialisierungsreihenfolge undefiniert ist. Deshalb will man solche statischen Initialisierungen nicht haben. Man verwendet deshalb lieber dynamische Initialisierungen - die stattfinden wenn sie benoetigt werden. zB Singletons.
Deshalb gibt es zB auch das Phoenix Idiom fuer Singletons - weil das destruieren der Objekte auch ein riesen Problem ist.
Das bedeutet: wenn dein feature umgesetzt werden wuerde (bedenke: es wuerde keine funktionalitaet hinzufuegen) wuerde es dennoch niemand verwenden - weil eben die Initialisierungsreihenfolge undefiniert ist und somit statische Konstruktoren sehr gefaehrlich waeren.
zB ein WSAStartup duerfte nicht in einem statischen Ctor sein - denn ich koennte ja ein Socket in einem anderen statischen Ctor erstellen wollen...
Deshalb funktioniert das einfach nicht. Es gibt bessere Loesungen. zB bei WSAStartup loest man es so, dass die Socket Klasse im Ctor einfach
ensure_wsastartup_was_called() aufruft, welches falls notwendig WSAStartup aufruft.