Wann werden statische Variablen auf Funktionsebene zugewiesen/initialisiert?
Frage
Ich bin ziemlich sicher, dass global deklarierte Variablen beim Programmstart zugewiesen (und ggf. initialisiert) werden.
int globalgarbage;
unsigned int anumber = 42;
Aber was ist mit statischen, die innerhalb einer Funktion definiert sind?
void doSomething()
{
static bool globalish = true;
// ...
}
Wann ist der Platz für globalish
zugeteilt?Ich schätze, wann das Programm startet.Aber wird es dann auch initialisiert?Oder wird es wann initialisiert? doSomething()
wird zuerst aufgerufen?
Lösung
Ich war neugierig auf diese so schrieb ich folgendes Testprogramm und kompiliert es mit g ++ Version 4.1.2.
include <iostream>
#include <string>
using namespace std;
class test
{
public:
test(const char *name)
: _name(name)
{
cout << _name << " created" << endl;
}
~test()
{
cout << _name << " destroyed" << endl;
}
string _name;
};
test t("global variable");
void f()
{
static test t("static variable");
test t2("Local variable");
cout << "Function executed" << endl;
}
int main()
{
test t("local to main");
cout << "Program start" << endl;
f();
cout << "Program end" << endl;
return 0;
}
Die Ergebnisse waren nicht das, was ich erwartet hatte. Der Konstruktor für das statische Objekt wurde nicht bis zum ersten Mal der Funktion aufgerufen aufgerufen wurde. Hier ist die Ausgabe:
global variable created
local to main created
Program start
static variable created
Local variable created
Function executed
Local variable destroyed
Program end
local to main destroyed
static variable destroyed
global variable destroyed
Andere Tipps
Einige relevante Wortschwall aus C ++ Standard:
3.6.2 Initialisierung nicht lokaler Objekte [basic.start.init]
1
Der Speicher für Objekte mit statischen Speicher Dauer ( basic.stc.static ) beträgt Null initialisiert ( dcl.init ) vor jeder anderen Initialisierung erfolgt. Objekte POD-Typen ( basic.types ) mit statischer Speicherdauer mit konstanten Ausdrücken initialisiert ( expr.const ) beträgt initialisiert, bevor eine dynamische Initialisierung stattfindet. Objekte Namespacebereich mit statischer Speicherdauer definiert in die gleiche Einheit Übersetzung und dynamisch initialisiert wird sein in der Reihenfolge, in der initialisiert ihre Definition erscheint in die Übersetzungseinheit. [Anmerkung: dcl.init.aggr beschreibt die Reihenfolge, in der Aggregat-Mitglieder initialisiert. Das Initialisierung lokaler statischer Objekte in stmt.dcl beschrieben. ]
[mehr Text mehr Freiheiten für Compiler Schriftsteller Hinzufügen]
6.7 Erklärung Anweisung [stmt.dcl]
...
4
Die Null-Initialisierung ( dcl.init ) alle lokalen Objekte mit statische Speicherdauer ( basic.stc.static ) wird vor andere Initialisierung erfolgt. Eine lokale Aufgabe POD-Typ ( basic.types ) mit statischer Speicherdauer initialisiert mit konstantem Ausdrücke initialisiert vor seinem Block wird zuerst eingegeben. Eine Implementierung erlaubt auszuführen Anfang Initialisierung von anderen lokalen Objekte mit statischen Speicher Dauer unter den gleichen Bedingungen, dass eine Implementierung ist gestattet statisch ein Objekt mit statischen Speicher zu initialisieren Dauer in Namespacebereich ( basic.start.init ). ansonsten solche Eine Aufgabe ist das erste Mal initialisiert Steuerung durchläuft seinen Erklärung; Ein solches Objekt betrachtet von der initialisiert wird Abschluss seiner Initialisierung. Wenn die Initialisierung beendet durch eine Ausnahme zu werfen, ist die Initialisierung nicht abgeschlossen ist, so wird es versucht werden, wieder das nächste Mal, Kontrolle der Erklärung eintritt. Wenn die Steuerung wieder in die Deklaration (rekursiv), während das Objekt zu sein, ist initialisiert, ist das Verhalten nicht definiert. [ Beispiel:
int foo(int i) { static int s = foo(2*i); // recursive call - undefined return i+1; }
- Ende Beispiel ]
5
Der Destruktor für ein lokales Objekt mit statischer Speicherdauer wird ausgeführt werden, wenn und nur wenn der Variable konstruiert. [Anmerkung: basic.start.term beschreibt die Reihenfolge, in der lokalen Objekte mit statischer Speicherdauer werden zerstört. ]
Der Speicher für alle statischen Variablen beim Programmlast zugeordnet. Aber lokale statische Variablen erstellt und initialisiert das erste Mal, wenn sie verwendet wird, nicht beim Programmstart. Es gibt einige gute Lektüre über das, und Statik in der Regel hier . Generell denke ich, einige dieser Probleme bei der Umsetzung abhängen, vor allem, wenn Sie, wo im Speicher wissen wollen diese Sachen befinden werden.
Der Compiler statischen Variable (n) zuweisen in einer Funktion foo
bei Programm Last definiert, aber der Compiler fügt auch einige zusätzliche Anweisungen (Maschinencode), um Ihre Funktion foo
, so dass das erste Mal, dass dieser zusätzliche Code aufgerufen wird, initialisieren der statischen variablen (zB den Konstruktor aufruft, wo zutreffend).
@ Adam:. Diese hinter den Kulissen Injektion von Code durch den Compiler ist der Grund für das Ergebnis, das Sie sah
Ich versuche, wieder zu testen Code von Adam Pierce und fügte zwei weitere Fälle: statische Variable in der Klasse und POD-Typ. Mein Compiler g ++ 4.8.1 unter Windows OS (MinGW-32). Das Ergebnis wird statischer Variable in der Klasse wird mit demselben globalen Variablen behandelt. Der Konstruktor wird aufgerufen werden, bevor Hauptfunktion eingegeben werden.
-
Schlussfolgerung (für g ++, Windows-Umgebung):
- Globale Variable und statisches Element in der Klasse : Konstruktor vor eingeben main aufgerufen wird Funktion (1) .
- Lokale statische Variable :. Konstruktor nur aufgerufen wird, wenn die Ausführung seiner Erklärung zum ersten Mal erreicht
- Wenn Lokale statische Variable ist der Typ POD , dann wird es auch vor Eingabe Haupt Funktion initialisiert (1) . Beispiel für POD-Typ: static int number = 10;
(1) : Der richtige Zustand sein sollte. "bevor eine Funktion aus der gleichen Übersetzungseinheit werden als" jedoch für einfache, wie im Beispiel unten, dann ist es main Funktion.
schließen
#include < string>
using namespace std;
class test
{
public:
test(const char *name)
: _name(name)
{
cout << _name << " created" << endl;
}
~test()
{
cout << _name << " destroyed" << endl;
}
string _name;
static test t; // static member
};
test test::t("static in class");
test t("global variable");
void f()
{
static test t("static variable");
static int num = 10 ; // POD type, init before enter main function
test t2("Local variable");
cout << "Function executed" << endl;
}
int main()
{
test t("local to main");
cout << "Program start" << endl;
f();
cout << "Program end" << endl;
return 0;
}
Ergebnis:
static in class created
global variable created
local to main created
Program start
static variable created
Local variable created
Function executed
Local variable destroyed
Program end
local to main destroyed
static variable destroyed
global variable destroyed
static in class destroyed
Wer in Linux env getestet?
Statische Variablen sind in einem Code-Segment zugeordnet -. Sie sind Teil des ausführbaren Bildes sind, und so abgebildet werden, in bereits initialisiert
Statische Variablen innerhalb Funktionsumfang werden gleich behandelt, die Scoping ist eine reine Sprachniveau Konstrukt.
Aus diesem Grunde werden Sie garantiert, dass eine statische Variable wird auf 0 initialisiert werden, anstatt einen nicht definierten Wert (es sei denn, Sie etwas anderes angeben).
Es gibt einige andere Facetten der Initialisierung Sie die Vorteile aus nehmen können -. Für die Segmente Beispiel geteilt erlauben verschiedene Instanzen die ausführbare Datei ausgeführt wird auf einmal die gleichen statischen Variablen zugreifen
In C ++ (scoped global) statische Objekte haben ihre Erbauer genannt als Teil des Programms starten, unter der Kontrolle der C-Laufzeitbibliothek. Unter Visual C ++ zumindest die Reihenfolge, dass Objekte, die von der init_seg Pragma.
Oder ist es initialisiert, wenn doSomething () aufgerufen wird zuerst?
Ja, es ist. Dies unter anderem, können Sie initialisieren global zugegriffen Datenstrukturen, wenn es angebracht ist, zum Beispiel innerhalb try / catch-Blöcke. Z.B. anstelle von
int foo = init(); // bad if init() throws something
int main() {
try {
...
}
catch(...){
...
}
}
Sie können schreiben
int& foo() {
static int myfoo = init();
return myfoo;
}
und verwenden Sie es innerhalb des try / catch-Block. Beim ersten Aufruf wird die Variable initialisiert. Dann wird auf dem ersten und die nächsten Anruf, wird sein Wert (Referenz) zurückgeführt werden.