2014-11-29 11 views
10

A recent question lenkte meine Aufmerksamkeit auf die Art, wie constexpr has changed in C++14. Das neue Feature ist, dass eine nicht lokale Variable mit statischer Speicherdauer in der statischen Initialisierungsphase initialisiert werden kann, wenn ihr Initialisierer aus einem constexpr Konstruktor besteht, selbst wenn der Typ der Variablen kein Literaltyp ist. Genauer gesagt, ist die neue Formulierung in [basic.start.init]:Zerstörungsreihenfolge von statisch initialisierten, nicht-literalen Objekten

A Konstante initializer für ein Objekt o ein Ausdruck ist, dass ein konstanter Ausdruck ist, mit der Ausnahme, dass es auch constexpr Konstrukteuren für o aufrufen kann und seine Unterobjekte, auch wenn diese Objekte nicht literale Klassen sind [Hinweis: eine solche Klasse kann einen nicht-trivialen Destruktor haben — Endnote]. Konstante Initialisierung wird ausgeführt, [...] wenn ein Objekt mit statischer oder Threadspeicherdauer durch einen Konstruktoraufruf initialisiert wird und der Initialisierungsvollausdruck ein Konstantinitialisierer für das [...] Objekt

ist

Das typische Beispiel ist std::unique_ptr, die „niemals schlechter sein, dass handschriftliche“:

std::unique_ptr<int> p; // statically initialized by [unique.ptr.single.ctor], 
          // requires no code excution 
int main() 
{ 
    p = std::make_unique<int>(100); 
} 

// p is destroyed eventually 

Vor dieser Zugabe wurde statisch initialisierten Variablen entweder von Referenztyp oder wörtlichen Objekttypen, und hatte daher trivial Destruktoren. Aber jetzt kann eine statisch initialisierte globale Variable einen nicht-trivialen Destruktor haben.

Wie wird solch ein Destruktoraufruf in Bezug auf die Destruktoren von dynamisch initialisierten globalen Objekten in Bezug auf andere statisch initialisierte Objekte angeordnet, und wie werden die Destruktoraufrufe sequenziert?

+1

Dies ist nicht neu in C++ 14; sogar der vorherige Wortlaut lässt dies zu. ('std :: mutex' hat einen 'constexpr'-Konstruktor, so dass er zB die statische Initialisierung nutzen kann.) –

+0

@TC .: Danke für die Klarstellung! –

Antwort

1

[basic.start.term]/1 (N4140) sagt:

Wenn ein Objekt statisch initialisiert wird, wird das Objekt in der gleichen Reihenfolge zerstört, als ob das Objekt dynamisch initialisiert wurde.

Wie ich verstehe, bedeutet dies, dass zum Zweck der determinig die Reihenfolge der Zerstörung, die all statische Initialisierung als dynamisch (geordnet oder ungeordnet) behandelt wird und die Destruktoren werden in umgekehrter Reihenfolge der Initialisierung genannt.

+0

Ja, richtig, aber für die dynamische Initialisierung gibt es eine Reihe von Regeln zum Ordnen (geordnet und ungeordnet). Wie passen statisch initialisierte Objekte angesichts dieser Regel in diese Ordnung? –

+0

Sie sehen, es heißt "Variablen mit geordneten Initialisierung definiert in einer einzelnen Übersetzungseinheit soll in der Reihenfolge ihrer Definition initialisiert werden". Aber das hilft nur, wenn die Initialisierung in Ordnung ist, was bei statisch initialisierten Variablen nicht der Fall ist. –

+0

@KerrekSB Ich denke, es ist ziemlich klar (aktualisiert meine Antwort), aber um ehrlich zu sein habe ich nicht getestet, ob das wirklich funktioniert, wie ich denke mit aktuellen Compilern –

3

Betrachten

Wenn ein Objekt statisch initialisiert wird, wird das Objekt in der gleichen Reihenfolge zerstört, als ob das Objekt dynamisch initialisiert wurde.

und

Wenn der Abschluß des Konstruktors oder dynamischer Initialisierung eines Objekt mit statischer Lagerdauer vor, dass die anderen sequenziert ist, werden die Beendigung des Destruktor der zweiten sequenziert, bevor die Initiation des Destruktors des ersten.Jetzt

,

Statische Initialisierung wird durchgeführt werden, bevor eine dynamische Initialisierung stattfindet.

eindeutig beantwortet dies die erste Frage: Da p garantiert initialisiert werden, bevor eine dynamische Initialisierung durchgeführt wird, die destructor nach jedes dynamisch initialisiert Objekt zerstört wird aufgerufen wird.

Wesentlichen die zweite Frage, dh welcher Reihenfolge die Zerstörungen von mehreren statisch initialisierten Variablen haben, auf die Reihenfolge der Initialisierung von diesen reduziert wird:

Dynamische Initialisierung eines nicht-lokale Variable mit statischen Speicher Dauer ist entweder geordnet oder ungeordnet. Definitionen von explizit spezialisierten statischen Datenelementen der Klassenvorlage haben Initialisierung bestellt. Andere statische Datenelemente von Klassenschablonen (d. H. implizit oder explizit instanziierte Spezialisierungen) haben eine ungeordnete Initialisierung. Andere nicht-lokale Variablen mit statischem Speicher Dauer haben die Initialisierung angeordnet.

Der fett formatierte Satz enthält alle statisch initialisierten Objekte, die keine statischen Datenelemente von instanziierten Klassen sind. Sie werden innerhalb einer Übersetzungseinheit bestellt:

Variablen mit geordneten Initialisierung innerhalb einer einzigen Übersetzungseinheit definiert ist, in der Reihenfolge ihrer Definitionen in der Übersetzungseinheit initialisiert werden.

also zusammenfassen:

  • Variablen, die Gegenstand der statischen Initialisierung sind und nicht statische Datenelemente eines instanziierten Klasse werden in umgekehrter Reihenfolge der Definition in einer Übersetzungsdatei zerstört.

  • ... diese Variablen werden immer zerstört, nachdem ein dynamisch initialisiertes Objekt zerstört wurde.

jedoch trotz möglichen argumentativen Fehler, weder Clang noch GCC scheint es auf diese Weise zur Zeit zu implementieren: Demo.

+0

Ist das von der C++ 14 (FD) IS? –

+0

@KerrekSB N4140, die offenbar nur redaktionelle Änderungen enthält. Lassen Sie mich überprüfen, ob der letzte Entwurf eingehalten wurde. – Columbo

+0

@KerrekSB (Alternativ, bieten Sie einen Link zu dem Dokument, das ich zitieren und überprüfen Sie diese Zitate gegen) – Columbo

Verwandte Themen