Statische Variablen in Mitgliedsfunktionen

158

Kann jemand bitte erklären, wie statische Variablen in Mitgliedsfunktionen in C ++ funktionieren.

Gegeben die folgende Klasse:

class A {
   void foo() {
      static int i;
      i++;
   }
}

Wenn ich mehrere Instanzen von deklariere A, foo()erhöht der Aufruf einer Instanz die statische Variable iauf allen Instanzen? Oder nur der, auf den es gerufen wurde?

Ich nahm an, dass jede Instanz eine eigene Kopie von haben würde i, aber das Durchgehen eines Codes, den ich habe, scheint etwas anderes anzuzeigen.

monofonik
quelle

Antworten:

169

Da class Aist eine Nicht-Vorlagenklasse und A::foo()ist eine Nicht-Vorlagenfunktion. Es wird nur eine Kopie static int iim Programm geben.

Jede Instanz eines AObjekts wirkt sich auf dasselbe aus iund die Lebensdauer ibleibt während des gesamten Programms erhalten. So fügen Sie ein Beispiel hinzu:

A o1, o2, o3;
o1.foo(); // i = 1
o2.foo(); // i = 2
o3.foo(); // i = 3
o1.foo(); // i = 4
iammilind
quelle
3
Danke für das gute Beispiel! Gibt es eine Möglichkeit, tatsächlich etwas zu erreichen, das den Umfang static int ider Instanz spezifisch macht , so dass z. B. o1.foo(); // i = 1und $o2.foo(); // i = 1...?
Stingery
14
Obwohl dies möglicherweise nicht der Stil ist, nach dem Sie suchen, hat die Erstellung eines privaten Datenmitglieds der Klasse A den von Ihnen beschriebenen Effekt. Wenn Sie über Namenskonflikte besorgt sind, können Sie ein Präfix hinzufügen m_, um den Status von i anzuzeigen.
Carl Morris
137

Das Schlüsselwort statichat in C ++ leider einige unterschiedliche Bedeutungen

  1. Bei Verwendung für Datenelemente bedeutet dies, dass die Daten in der Klasse und nicht in Instanzen zugewiesen werden .

  2. Bei Verwendung für Daten innerhalb einer Funktion bedeutet dies, dass die Daten statisch zugeordnet, beim ersten Eingeben des Blocks initialisiert und bis zum Beenden des Programms gültig sind. Auch die Variable ist nur innerhalb der Funktion sichtbar. Diese Besonderheit der lokalen Statik wird häufig verwendet, um die verzögerte Konstruktion von Singletons zu implementieren.

  3. Bei Verwendung auf Ebene der Kompilierungseinheit (Modul) bedeutet dies, dass die Variable wie eine globale Variable ist (dh zugewiesen und initialisiert, bevor sie mainausgeführt und nach dem mainBeenden zerstört wird ), dass die Variable jedoch in anderen Kompilierungseinheiten nicht zugänglich oder sichtbar ist .

Ich habe den Teil hervorgehoben, der für jede Verwendung am wichtigsten ist. Die Verwendung von (3) wird zugunsten nicht benannter Namespaces, von denen auch nicht exportierte Klassendeklarationen möglich sind, etwas abgeraten.

In Ihrem Code wird das staticSchlüsselwort mit der Bedeutung Nummer 2 verwendet und hat nichts mit Klassen oder Instanzen zu tun. Es ist eine Variable der Funktion und es wird nur eine Kopie davon geben.

Wie iammilind richtig sagte, hätte es jedoch mehrere Instanzen dieser Variablen geben können, wenn die Funktion eine Vorlagenfunktion gewesen wäre (da in diesem Fall die Funktion selbst tatsächlich in vielen verschiedenen Kopien im Programm vorhanden sein kann). Auch in diesem Fall sind Klassen und Instanzen natürlich irrelevant ... siehe folgendes Beispiel:

#include <stdio.h>

template<int num>
void bar()
{
    static int baz;
    printf("bar<%i>::baz = %i\n", num, baz++);
}

int main()
{
    bar<1>(); // Output will be 0
    bar<2>(); // Output will be 0
    bar<3>(); // Output will be 0
    bar<1>(); // Output will be 1
    bar<2>(); // Output will be 1
    bar<3>(); // Output will be 1
    bar<1>(); // Output will be 2
    bar<2>(); // Output will be 2
    bar<3>(); // Output will be 2
    return 0;
}
6502
quelle
41
+1 für keyword static unfortunately has a few different unrelated meanings in C++:)
iammilind
Die Welt macht so viel mehr Sinn, nachdem Sie dies gelesen haben. DANKE
Erin
Ich mag den Trick mit Vorlagen. Ich kann es kaum erwarten, eine Ausrede dafür zu finden.
Tomáš Zato - Wiedereinsetzung Monica
Hat jemand eine Referenz für "etwas entmutigt zugunsten unbenannter Namespaces"?
Austinmarton
3
@austinmarton: Der Ausdruck "Die Verwendung von statisch zur Angabe von" lokal zur Übersetzungseinheit "ist in C ++ veraltet. Verwenden Sie stattdessen unbenannte Namespaces (8.2.5.1)" ist in meiner Ausgabe (10. Druck, September 1999) in der Programmiersprache C ++ enthalten. auf Seite 819.
6502
2

Statische Variablen innerhalb von Funktionen

  • Die statische Variable wird innerhalb einer Funktion erstellt und im statischen Speicher des Programms gespeichert, nicht auf dem Stapel.

  • Die Initialisierung der statischen Variablen erfolgt beim ersten Aufruf der Funktion.

  • Die statische Variable behält den Wert in mehreren Funktionsaufrufen bei

  • Die Lebensdauer der statischen Variablen beträgt Programm

Geben Sie hier die Bildbeschreibung ein

Beispiele

#include <iostream>

using namespace std;

class CVariableTesting 
{
    public:
    
    void FuncWithStaticVariable();
    void FuncWithAutoVariable();

};

void CVariableTesting::FuncWithStaticVariable()
{
    static int staticVar = 0; //staticVar is initialised by 0 the first time
    cout<<"Variable Value : "<<staticVar<<endl;
    staticVar++;
}
void CVariableTesting::FuncWithAutoVariable()
{
    int autoVar = 0;
    cout<<"Variable Value : "<<autoVar<<endl;
    autoVar++;
}
    

int main()
{
    CVariableTesting objCVariableTesting;
    cout<<"Static Variable";
    objCVariableTesting.FuncWithStaticVariable();
    objCVariableTesting.FuncWithStaticVariable();
    objCVariableTesting.FuncWithStaticVariable();
    objCVariableTesting.FuncWithStaticVariable();
    objCVariableTesting.FuncWithStaticVariable();
    
    cout<<endl;
    cout<<"Auto Variable";
    objCVariableTesting.FuncWithAutoVariable();
    objCVariableTesting.FuncWithAutoVariable();
    objCVariableTesting.FuncWithAutoVariable();
    objCVariableTesting.FuncWithAutoVariable();
    objCVariableTesting.FuncWithAutoVariable();
    
    return 0;
}

Ausgabe :

Statische Variable

Variabler Wert: 0
Variabler Wert: 1
Variabler Wert: 2
Variabler Wert: 3
Variabler Wert: 4

Automatische Variable

Variablenwert: 0
Variablenwert: 0
Variablenwert: 0
Variablenwert: 0
Variablenwert: 0

Saurabh Raoot
quelle
-2

Vereinfachte Antwort:

Statische Variablen classverhalten sich - unabhängig davon, ob sie Mitglieder einer Funktion (ohne Vorlage) oder einer Funktion (ohne Vorlage) sind - technisch gesehen - wie eine globale Bezeichnung, deren Gültigkeitsbereich auf die classFunktion oder beschränkt ist.

0xbadf00d
quelle
9
Nein. Globals werden beim Programmstart initialisiert, Funktionsstatiken werden bei der ersten Verwendung initialisiert. Das ist ein großer Unterschied.
6502
Ich glaube nicht, dass das passiert. Dies sollte jedoch ohnehin compilerspezifisch sein.
0xbadf00d
2
Dann denken Sie falsch: 3.6.1 im C ++ - Standard schreibt vor, dass die Erstellung eines Objekts mit Namespace-Bereich und statischer Speicherdauer beim Start erfolgt. 6.7 (4) schreibt vor, dass im Allgemeinen "... eine solche Variable beim ersten Durchlauf der Kontrolle durch ihre Deklaration initialisiert wird; eine solche Variable gilt nach Abschluss ihrer Initialisierung als initialisiert". Übrigens ist diese Initialisierung bei der ersten Verwendung sehr praktisch, um eine verzögerte Singleton-Konstruktion zu implementieren.
6502
3.7.4: "Die konstante Initialisierung (3.6.2) einer Blockbereichsentität mit statischer Speicherdauer, falls zutreffend, wird vor der ersten Eingabe ihres Blocks durchgeführt. Eine Implementierung kann eine frühzeitige Initialisierung anderer Blockbereichsvariablen mit durchführen statische oder Thread-Speicherdauer unter den gleichen Bedingungen, unter denen eine Implementierung eine Variable mit statischer oder Thread-Speicherdauer im Namespace-Bereich (3.6.2) statisch initialisieren darf. Andernfalls wird eine solche Variable initialisiert, wenn die Steuerung ihre Deklaration zum ersten Mal durchläuft. "
0xbadf00d
1
Seltsamerweise jedoch: 1) Für eine konstante Initialisierung ist es irrelevant zu diskutieren, ob eine lokale Statik vor dem ersten Betreten des Blocks initialisiert werden kann (die Variable ist nur innerhalb des Blocks sichtbar und eine konstante Initialisierung erzeugt keine Nebenwirkungen). 2) In Ihrem Beitrag wird nichts über die ständige Initialisierung gesagt. 3) Lokale Statik ist sehr nützlich für nicht konstante Initialisierung wie MyClass& instance(){ static MyClass x("config.ini"); return x; }- eine gültige tragbare Implementierung für die Verwendung mit einem Thread, genau weil lokale Statik trotz Ihrer Aussagen NICHT einfach wie eine globale ist.
6502