/ / In welche Dateien muss iostream aufgenommen werden? - c ++, c ++ 11

In welche Dateien muss Iostream aufgenommen werden? - C ++, C ++ 11

Ich habe ein schnelles Beispiel geschrieben, um die Initialisierung / Zerstörung globaler Objekte zu demonstrieren. Dabei stieß ich auf folgendes Rätsel.

Im Allgemeinen sollten Sie keine Header in eine Headerdatei einfügen, die nicht für den Code in der Headerdatei erforderlich sind. Dies verringert die Verwirrung und die Kompilierzeit.

In meinem Beispiel spalte ich die Definition vonKonstruktor und Destruktor aus der Klassendefinition. In meinem Fall sind sie so trivial, dass ich sie wahrscheinlich nur einreihen würde.

Die Übersetzungseinheit, die den Konstruktor und den Destruktor tatsächlich definiert, umfasst iostream damit er Anrufe an die Konsole ausgeben kann.

Wo meine Frage ankommt, wann wir beginnenIch spreche davon, Instanzen meiner Klasse im globalen Bereich zu deklarieren. Jetzt laufe ich auf Initialisierungsreihenfolge und Übersetzungseinheiten. Die Reihenfolge der Initialisierung globaler Variablen innerhalb einer Übersetzungseinheit ist gut definiert. Die Reihenfolge der Initialisierung globaler Variablen von einer Übersetzungseinheit zur anderen ist weniger genau festgelegt. In meinem Beispiel kann es eine der folgenden Aktionen ausführen:

  • Initialisieren Sie die erste Quelldatei und dann die zweite Quelldatei.
  • Initialisieren Sie die zweite Quelldatei und dann die erste Quelldatei.
  • Initialisieren Sie die zweite Quelldatei.

24.4.1 / 2: Die Objekte [std :: cout in meinem Fall] werden aufgebaut und die Assoziationen werden irgendwann vor oder während der ersten Zeit eines Klassenobjekts hergestellt ios_base::Init ist konstruiert, und in jedem Fall, bevor der Hauptteil der Ausführung beginnt. Die Objekte werden während der Programmausführung nicht zerstört. Die Ergebnisse des Einschlusses <iostream> in einer Übersetzungseinheit soll es so sein <iostream> definierte eine Instanz von ios_base::Init mit statischer Lagerdauer. Ebenso soll sich das gesamte Programm so verhalten, als ob mindestens eine Instanz von ios_base::Init mit statischer Lagerdauer.

Beachten Sie, dass dieser Absatz die as-if-Regel aufruft, sodass keine Instanz von erstellt werden muss ios_base::Initaber es muss sich so verhalten, als ob es tat

Angenommen, der Compiler und die StandardbibliothekWenn Sie sich wie im Absatz angegeben verhalten und nichts anderes als Äquivalent tun, scheint die einzige für mein Programm gültige Initialisierungsreihenfolge die Initialisierung der ersten und dann der zweiten Quelldatei zu sein. Andernfalls wurde std :: cout nicht vor dem Versuch initialisiert.

Header-Datei:

#ifndef HEADER_H_
#define HEADER_H_

struct A {
A(const char*);
~A();
const char* v;
}

#endif

Erste Quelldatei:

#include "header.h"
#include <iostream>

A::A(const char* val) : v{ val } {
std::cout << v << "n";
}
~A() {
std::cout << "~" << v << "n";
}

A a{ "a" };
A b{ "b" };

Zweite Quelldatei:

#include "header.h"

A c{ "c" };
A d{ "d" };

int main() {
}

Antworten:

0 für die Antwort № 1

Beim Schreiben dieser Frage wurde mir klar, dass die Antwort in 3.6.2 / 4 enthalten ist.

Es ist implementierungsabhängig, ob die DynamikDie Initialisierung einer nicht lokalen Variablen mit statischer Speicherdauer erfolgt vor der ersten Anweisung von main. Wenn die Initialisierung auf einen Zeitpunkt nach der ersten Anweisung von main verschoben wird, erfolgt sie vor der ersten Verwendung einer Funktion oder Variablen, die in derselben Übersetzungseinheit wie die zu initialisierende Variable definiert ist.

Dies bedeutet, dass der Aufruf des Konstruktors von auch dann, wenn die zweite Quelldatei gerade initialisiert werden soll c bewirkt, dass die erste Quelldatei initialisiert wird, bevor der Konstruktor tatsächlich ausgeführt wird c. Dies garantiert, dass die Reihenfolge der statischen Initialisierung lautet:

  1. ios_base::Init
  2. a
  3. b
  4. c
  5. d

Da die Initialisierungsreihenfolge nicht eindeutig ist, besteht kein Problem.