2017-11-30 1 views
4

Wenn ich habe folgende A.h Datei (Header only):Müssen statische Inline-Variablen vor main initialisiert werden?

#pragma once 

struct A{ 
    static inline struct Initializer{ 
    Initializer(){ 
     std::cout << "init A" << std::endl; 
    } 
    } initializer; 
}; 

es genug, um #include "A.h" ist (von einem anderen Header, der von main.cpp enthalten sein wird), so Initializer::Initializer() vor main() genannt werden?

Ich lese, dass Standard erfordert, statische Variablen mit dynamischer Initialisierung erst vor seiner Verwendung zu initialisieren.

Es ist die Implementierung definiert, ob die dynamische Initialisierung (8.5, 9.4, 12.1, 12.6.1) eines Objekts von Namespacebereich ist vor der ersten Anweisung des Haupt getan. Wenn die Initialisierung zu einem Zeitpunkt nach der ersten Hauptaussage auf zurückgestellt wird, muss sie vor der ersten Verwendung einer Funktion oder eines Objekts erfolgen, die in der gleichen Übersetzungseinheit wie das zu initialisierende Objekt definiert sind.

Wird #include als "Verwendung" betrachtet?

+2

Lokale statische Variablen (interne Funktionen) werden initialisiert, wenn die Funktion zum ersten Mal aufgerufen wird. Alle anderen statischen Variablen werden initialisiert, bevor 'main' aufgerufen wird. –

+0

'#include" file "' bedeutet nur "füge den Inhalt von 'file' hier ein". Es verhält sich genau so, als wenn Sie stattdessen copy and paste verwendet hätten (aber beim Berichten von Diagnosen die Zeilennummern anpassen). – molbdnilo

+0

@Someprogrammerdude Ich denke nicht, dass das wahr ist ... http://en.cppreference.com/w/cpp/language/initialization siehe "Deferred dynamische Initialisierung" – tower120

Antwort

3

Der neueste Arbeitsentwurf hat explizitere Formulierung in [basic.start.dynamic]/5:

Es ist die Implementierung definiert, ob die dynamische Initialisierung eines nicht-lokalen Inline-Variable mit statischer Lagerdauer vor der ersten Anweisung des Hauptes sequenziert oder ist aufgeschoben. Wenn es zurückgestellt wird, passiert es stark vor jeder nicht-Initialisierung odr-Verwendung dieser Variablen. Es ist implementierungsdefiniert, in welchen Threads und an welchen Stellen des Programms eine solche verzögerte dynamische Initialisierung stattfindet.

Wo:

Eine nicht-Initialisierung ODR-use ist eine ODR-use ([basic.def.odr]), die nicht direkt oder indirekt durch die Initialisierung eines nicht-lokale statischen verursacht oder Thread-Speicherdauervariable.


So Ihre Frage zu beantworten:

Ist es genug "Ah", um # include (von einem anderen Header, der von main.cpp aufgenommen werden), so Initializer::Initializer() vor aufgerufen werden Main()?

Nr. #include ist nicht genug. Sie müssen eigentlich odr-use es.

0

Wie ich lesen Sie die Website von tower120 in den Kommentaren der Frage zur Verfügung gestellt ich dies gefunden:

Alle nicht-lokale Variablen mit statischer Speicherdauer als Teil der Programmstart initialisiert werden, wird vor der Ausführung der Hauptfunktion beginnt (sofern nicht aufgeschoben, siehe unten).

http://en.cppreference.com/w/cpp/language/initialization

Wenn Ihre statische Initialisierung der Variablen verschoben werden würde, die gleiche Seite sagt

Wenn die Initialisierung eines Inline-Variable verschoben wird, kommt es vor dem ersten odr-Einsatz, dass spezifische Variable.

"odr-uses" sind Fälle, in denen auf die Adresse einer Variablen oder Funktion zugegriffen wird (über Zeiger oder Referenz). Also, wenn Sie A::Initializer::Initializer() wollen, bevor main() aufgerufen werden Sie es zuweisen Adresse (Zeiger der Referenz) zu einer nicht-latenten statischen Variablen, die A::Initializer s erste ord-Nutzung und A::Initializer::Initializer() 's Anruf vor main() passieren verursachen würde

#include wird auch nicht als "verwenden", sondern als "einfügen". Die Include-Anweisung kopiert den gesamten Inhalt der Datei an ihrer Position.

Hier ist ein einfaches Beispiel:

A. h

public class A { 
    public: 
     A() {}; 
    private: 
     int var; 
} 

main.

cpp
#include "A.h" 
int main() 
{ 
    //Some Code 
} 

wird diese

public class A { 
    public: 
     A() {}; 
    private: 
     int var; 
} 
int main() 
{ 
    //Some Code 
} 

geworden Deshalb sollten Sie Wächter oder #pragma once müssen, gehören zwei Dateien mit dem gleichen Header-Code zu verhindern zweimal eine Klasse oder Variable zu definieren.

+0

Was wäre, wenn main.cpp '#include Ah' hätte nach * dem Ende von 'main()' und hat 'struct A' überhaupt nicht benutzt. Würde der Konstruktor 'A :: Initialisator :: Initializer()' noch aufgerufen? – DodgyCodeException

+1

Die Reihenfolge der Funktionen in Ihrem Code hat keinen Einfluss auf die Reihenfolge der Aufrufe in Ihrer Logik, oder? Der zitierte Text erwähnt auch, dass alle nicht-lokalen Variablen initialisiert werden "vor der Ausführung der Hauptfunktion". Und Konstruktoren werden aufgerufen, um etwas zu initialisieren. Also ja, 'A :: Initialisierer :: Initialisierer()' sollte immer noch vor 'main()' aufgerufen werden, wenn Sie '#include" A.h "' hinter 'main()' setzen. – Detonar

+0

Dies ist der Fall der "dynamischen Initialisierung". Weil "Initialisierer" nicht statisch konstruiert werden kann (Nebenwirkungen haben). Daher ist es erlaubt, dies zu ändern. – tower120

Verwandte Themen