Beispiel:
struct Foo { Foo() { printf("foo\n"); } };
static Foo foo;
__attribute__((constructor)) static void _bar() { printf("bar\n"); }
Ist es deterministisches Wetter? foo
oder bar
wird zuerst gedruckt?
(Ich hoffe und würde erwarten, dass Konstruktoren von statischen Objekten immer zuerst ausgeführt werden, bin mir aber nicht sicher, und das GCC-Dokument über das Konstruktorattribut sagt nichts darüber aus.)
foo
wird zuerst gedruckt, da die Objekte in der Reihenfolge ihrer Deklarationen initialisiert werden. Laufen und sehen:
Übrigens, __attribute__((constructor))
ist kein Standard-C++. Es ist die Erweiterung von GCC. Das Verhalten Ihres Programms hängt also davon ab, wie GCC es definiert hat. Kurz gesagt, es ist demnach implementierungsdefiniert foo
wird zuerst gedruckt.
Das Dok sagt,
Das Konstruktorattribut bewirkt, dass die Funktion automatisch aufgerufen wird, bevor die Ausführung in main() eintritt. In ähnlicher Weise bewirkt das Destruktor-Attribut, dass die Funktion automatisch aufgerufen wird, nachdem main() abgeschlossen oder exit() aufgerufen wurde. Funktionen mit diesen Attributen sind nützlich, um Daten zu initialisieren, die während der Ausführung des Programms implizit verwendet werden.
Sie können optional eine ganzzahlige Priorität angeben, um die Reihenfolge zu steuern, in der Konstruktor- und Destruktorfunktionen ausgeführt werden. Ein Konstruktor mit einer kleineren Prioritätszahl läuft vor einem Konstruktor mit einer größeren Prioritätszahl; die umgekehrte Beziehung gilt für Destruktoren. Wenn Sie also einen Konstruktor haben, der eine Ressource zuweist, und einen Destruktor, der dieselbe Ressource freigibt, haben beide Funktionen normalerweise dieselbe Priorität. Die Prioritäten für Konstruktor- und Destruktorfunktionen sind die gleichen wie die, die für C++-Objekte im Namespace-Bereich angegeben sind (siehe C++-Attribute).
Ich denke, der fettgedruckte Text impliziert, dass die Objekte in der Reihenfolge ihrer Deklarationen initialisiert werden, wie ich bereits sagte, was durch ziemlich genau bestätigt wird Online-Demo Auch.
Ich nehme an, Sie möchten das auch lesen:
Wenn Sie die Initialisierungsreihenfolge steuern/ändern möchten, können Sie verwenden init_priority
Attribut, Bereitstellung Priorität. Genommen von die Seite:
Some_Class A __attribute__ ((init_priority (2000)));
Some_Class B __attribute__ ((init_priority (543)));
Hier, B
vorher initialisiert wird A
.
Es ist nicht durch den Standard definiert, aber hier ist mein Experiment https://github.com/SanSanch5/static-initialization-order-example
Die Ausgabe auf gcc-9:
CFoo constructed
dll constructor
CBaz constructed
CBar constructed
foo
dll destructor
CBar destructed
CBaz destructed
CFoo destructed
Die Ausgabe auf clang-12:
CFoo constructed
dll constructor
CBaz constructed
CBar constructed
foo
CBar destructed
dll destructor
CBaz destructed
CFoo destructed
Der DLL-Konstruktor wird also vor der statischen Initialisierung aufgerufen, aber wie Sie sehen können, ist die Zerstörung bei gcc und clang etwas anders. Aber die Initialisierung eines statischen Objekts innerhalb eines DLL-Konstruktors beweist experimentell seine Zerstörung nach den anderen statischen Objekten. Aber es ist kein Standard, also nicht zuverlässig.
Wo verwenden Sie solche Compiler-Features?
– AlexTheo
9. Dezember 2011 um 15:47 Uhr
@AlexTheo: Das ist durchaus üblich. Siehe zB <codesearch.google.com/#search/…>. Sie verwenden es normalerweise jedes Mal, wenn Sie etwas initialisieren möchten.
– Albert
9. Dezember 2011 um 15:51 Uhr
Eigentlich bevorzuge ich so etwas wie static const bool _isInitialized und das Erstellen einer privaten Initialisierungsfunktion, mit der ich mein Objekt wie const bool MyClass::_isInitialized = initFunction(); Aber das ist nur für Objekte, die ich zuerst initialisieren möchte. Andernfalls sollte der Konstruktor einen Job erledigen.
– AlexTheo
9. Dezember 2011 um 16:10 Uhr
@AlexTheo Dieser Ansatz funktioniert in C nicht. Sicher können Sie einen Konstruktor in C++ verwenden, aber dies hat den gleichen Effekt wie ein statischer Initialisierer in C.
– Nevelis
28. September 2012 um 6:08 Uhr
@nevelis wir reden über c++!!!
– AlexTheo
28. September 2012 um 10:24 Uhr