Betrachten Sie den folgenden Code, der auf drei Kompilierungseinheiten aufgeteilt ist:
a.h
:
struct A
{
void Register(const char* s);
const char* m_s[10];
int m_i = 0;
};
A& GetA();
a.cpp
:
#include "a.h"
#include <stdio.h>
void A::Register(const char* s)
{
m_s[m_i++] = s;
}
A& GetA()
{
static A instance;
return instance;
}
int main(int argc, char* argv[])
{
A& a = GetA();
int n = a.m_i;
for (int i = 0; i < n ; ++i)
printf("%sn", a.m_s[i]);
return 0;
}
b.cpp
:
#include "a.h"
struct B
{
B() { GetA().Register("b"); }
static B* instance;
};
B* B::instance = new B;
c.cpp
:
#include "a.h"
struct C
{
C() { GetA().Register("c"); }
static C* instance;
};
C* C::instance = new C;
Der Code wird mit gcc (-std = c ++ 11) erstellt und ausgeführt und erzeugt die Ausgabe:
c
b
Nun, bezogen auf cppreference.com:
Verzögerte dynamische Initialisierung
Es ist implementierungsdefiniert, ob dynamischInitialisierung passiert - vor der ersten Aussage der Hauptfunktion (für Statik) oder die anfängliche Funktion des Threads (für Thread-Locals) oder verzögert nach dem geschehen
Bei der Initialisierung einer Nicht-Inline-Variablenist verzögert nach der ersten Anweisung der Haupt- / Thread-Funktion, es geschieht vor der ersten odr-Verwendung einer Variablen mit static / thread Speicherdauer, die in derselben Übersetzungseinheit wie die Variable definiert ist initialisiert werden. Wenn keine Variable oder Funktion aus einem gegebenen Wert verwendet wird Übersetzungseinheit, die in dieser Übersetzung definierten nichtlokalen Variablen Die Einheit darf niemals initialisiert werden (dies modelliert das Verhalten einer dynamische On-Demand-Bibliothek). Allerdings solange nichts von einer TU ist odr-verwendet alle nicht lokalen Variablen, deren Initialisierung oder Zerstörung hat Nebenwirkungen werden auch dann initialisiert, wenn sie nicht im Internet verwendet werden Programm.
Beachten Sie, dass a.cpp
ist sich der Existenz von nicht bewusst B
und C
und dass die einzigen Wechselwirkungen von B
& C
mit A
sind die Aufrufe von GetA()
und A::Register()
während der Konstruktion ihrer jeweiligen Instanzen.
Soweit ich sehen kann, die B
& C
Instanzen werden nicht von ODR verwendet und schon gar nicht von main()
s Übersetzungseinheit. Ihre Initialisierung hat eindeutig Nebenwirkungen, aber es scheint mir, dass es keine Garantie dafür gibt, dass diese Initialisierung vor dem Einstieg erfolgt main()
, oder davor main()
druckt die registrierten Zeichenfolgen - oder überhaupt.
So endlich - Meine Frage ist das: Ist die Tatsache, dass die B
und C
Instanzen werden vorher initialisiert main()
gibt die registrierten Zeichenfolgen aus nicht zum Standard, aber zu gccs implementierungsdefiniertem Verhalten?
Wenn der Standard dies garantiert, wie?
Antworten:
0 für die Antwort № 1Ist die Tatsache, dass die
B
undC
Instanzen werden vorher initialisiertmain()
druckt die registrierten Zeichenfolgen nicht nach dem Standard, sondern nach dem von gcc implementierten Verhalten
Es ist nicht garantiert durch standard. Der relevanteste Teil des Zitats:
Wenn keine Variable oder Funktion aus einer gegebenen Übersetzungseinheit verwendet wird, können die in dieser Übersetzungseinheit definierten nicht lokalen Variablen niemals initialisiert werden
Da keine Funktion oder Variable verwendet wurde b.cpp
Noch c.cpp
Ihre statischen Variablen sind möglicherweise (hinsichtlich der dynamischen Initialisierung) nicht initialisiert, und daher sind die Nebenwirkungen ihrer Initialisierung möglicherweise nicht sichtbar.
In der Praxis würde ich die gezeigten erwarten,Initialisierungsverhalten, wenn die Übersetzungseinheiten statisch verknüpft sind, und das mögliche Nichtinitialisierungsverhalten, wenn sie dynamisch geladen werden (gemeinsam genutzte Bibliothek). Der Standard garantiert jedoch keine, da er nicht das Verhalten von gemeinsam genutzten Bibliotheken angibt.