419 Stimmen

Was ist die Lebensdauer einer statischen Variablen in einer C++-Funktion?

Wenn eine Variable deklariert ist als static im Geltungsbereich einer Funktion wird sie nur einmal initialisiert und behält ihren Wert zwischen Funktionsaufrufen bei. Was genau ist seine Lebensdauer? Wann werden der Konstruktor und der Destruktor aufgerufen?

void foo() 
{ 
    static string plonk = "When will I die?";
}

301voto

Motti Punkte 104854

Die Lebensdauer der Funktion static Variablen beginnt das erste Mal [0] der Programmablauf trifft auf die Deklaration und endet bei Programmende. Das bedeutet, dass die Laufzeit eine Buchführung durchführen muss, um sie nur dann zu zerstören, wenn sie tatsächlich konstruiert wurde.

Da der Standard außerdem besagt, dass die Destruktoren statischer Objekte in der umgekehrten Reihenfolge der Fertigstellung ihrer Konstruktion ablaufen müssen [1] Da die Reihenfolge des Aufbaus vom jeweiligen Programmablauf abhängen kann, muss die Reihenfolge des Aufbaus berücksichtigt werden.

Beispiel

struct emitter {
    string str;
    emitter(const string& s) : str(s) { cout << "Created " << str << endl; }
    ~emitter() { cout << "Destroyed " << str << endl; }
};

void foo(bool skip_first) 
{
    if (!skip_first)
        static emitter a("in if");
    static emitter b("in foo");
}

int main(int argc, char*[])
{
    foo(argc != 2);
    if (argc == 3)
        foo(false);
}

Sortie :

C:>Muster.exe
Erstellt in foo
Zerstört in foo

C:>Muster.exe 1
Erstellt in if
Erstellt in foo
Zerstört in foo
Zerstört in wenn

C:>Muster.exe 1 2
Erstellt in foo
Erstellt in if
Zerstört in wenn
Zerstört in foo

[0] Seit C++98 [2] hat keinen Verweis auf mehrere Threads, wie sich dies in einer Multi-Thread-Umgebung verhalten wird, ist nicht spezifiziert und kann problematisch sein, da Roddy Erwähnungen.

[1] C++98 Abschnitt 3.6.3.1 [basic.start.term]

[2] In C++11 werden Statiken auf eine thread-sichere Weise initialisiert, dies ist auch bekannt als Magische Statik .

134voto

Roddy Punkte 64661

Motti hat Recht, was die Reihenfolge angeht, aber es gibt noch einige andere Dinge zu beachten:

Compiler verwenden in der Regel eine versteckte Flag-Variable, um anzuzeigen, ob die lokale Statik bereits initialisiert wurde, und dieses Flag wird bei jeder Eingabe in die Funktion überprüft. Dies ist natürlich ein kleiner Leistungseinbruch, aber noch bedenklicher ist, dass dieses Flag nicht garantiert thread-sicher ist.

Wenn Sie ein lokales Static wie oben haben und foo von mehreren Threads aus aufgerufen wird, können Race Conditions auftreten, die plonk falsch oder sogar mehrfach initialisiert werden. Auch in diesem Fall plonk kann von einem anderen Thread zerstört werden als dem, der es erstellt hat.

Ungeachtet dessen, was der Standard sagt, wäre ich sehr vorsichtig, was die tatsächliche Reihenfolge der Zerstörung lokaler statischer Elemente angeht, denn es ist möglich, dass man sich unwissentlich darauf verlässt, dass ein statisches Element noch gültig ist, nachdem es zerstört wurde, und das ist wirklich schwer nachzuvollziehen.

10voto

Ben Voigt Punkte 268424

Die bisherigen Erläuterungen sind ohne die eigentliche Regel aus der Norm, die sich in 6.7 findet, nicht wirklich vollständig:

Die Null-Initialisierung aller Block-Scope-Variablen mit statischer Speicherdauer oder Thread-Speicherdauer wird vor jeder anderen Initialisierung durchgeführt. Die konstante Initialisierung einer Block-Scope-Entität mit statischer Speicherdauer wird, falls zutreffend, durchgeführt, bevor ihr Block zum ersten Mal betreten wird. Eine Implementierung darf eine frühzeitige Initialisierung anderer Block-Scope-Variablen mit statischer oder Thread-Speicherdauer unter denselben Bedingungen durchführen, unter denen eine Implementierung eine Variable mit statischer oder Thread-Speicherdauer im Namespace-Bereich statisch initialisieren darf. Andernfalls wird eine solche Variable beim ersten Kontrolldurchlauf durch ihre Deklaration initialisiert; eine solche Variable gilt als initialisiert, sobald ihre Initialisierung abgeschlossen ist. Wenn die Initialisierung durch das Auslösen einer Ausnahme beendet wird, ist die Initialisierung nicht abgeschlossen und wird daher beim nächsten Durchlaufen der Deklaration erneut versucht. Wenn die Steuerung die Deklaration gleichzeitig betritt, während die Variable initialisiert wird, muss die gleichzeitige Ausführung auf den Abschluss der Initialisierung warten. Wenn das Steuerelement die Deklaration rekursiv erneut betritt, während die Variable initialisiert wird, ist das Verhalten undefiniert.

8voto

Roddy Punkte 64661

FWIW, Codegear C++Builder zerstört sich nicht in der erwarteten Reihenfolge gemäß dem Standard.

C:\> sample.exe 1 2
Created in foo
Created in if
Destroyed in foo
Destroyed in if

... was ein weiterer Grund ist, sich nicht auf die Vernichtungsanordnung zu verlassen!

0voto

Chandra Shekhar Punkte 553

Le site Statische Variablen kommen ins Spiel, sobald die Programmausführung beginnt und bleibt bis zum Ende der Programmausführung verfügbar.

Die statischen Variablen werden in der Datei Datensegment des Speichers .

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X