2016-05-06 5 views
0

Sagen wir, ich erstellen:Gibt es ein Risiko, dass die lokale statische Variable einer Methode zwischen Instanzen geteilt wird?

class Hello { 
    public: 
     int World(int in) 
     { 
      static int var = 0; // <<<< This thing here. 
      if(in >= 0) { 
       var = in; 
      } else { 
       cout << var << endl; 
      } 
     } 
}; 

Nun, wenn ich tun:

Hello A; 
Hello B; 

A.World(10); 
A.World(-1); 
B.World(-1); 

Ich bin Ausgabe von "10" durch einen anderen "10", gefolgt bekommen. Der Wert der lokalen Variablen einer Methode, die gerade von einer Instanz einer Klasse auf eine andere übertragen wurde.

Es ist nicht überraschend - technisch Methoden sind nur Funktionen mit einem versteckten this Parameter, so sollte eine statische lokale Variable genau wie in gemeinsamen Funktionen verhalten. Aber ist es garantiert? Ist es ein Verhalten, das durch den Standard erzwungen wird, oder ist es lediglich ein glückliches Nebenprodukt davon, wie der Compiler mit Methoden umgeht? Mit anderen Worten - ist dieses Verhalten sicher zu verwenden? (... über das Standardrisiko hinaus, jemanden zu verwirren, der nicht gewusst hat ...)

Antwort

3

Ja. Es spielt keine Rolle, ob die Funktion ein [nicht-statisches] Mitglied einer Klasse ist oder nicht, es ist garantiert, nur eine Instanz ihrer statischen Variablen zu haben.

Die richtige technische Erklärung für solche Variablen ist, dass diese Objekte Objekte mit static duration und internal linkage sind - und diese Namen bleiben also bestehen, bis das Programm beendet wird, und alle Instanzen dieses Namens beziehen sich auf dieselbe Entität.

+0

Ebenso wichtig wie die Speicherdauer ist die Tatsache, dass der Name 'var' jetzt * interne Verknüpfung * hat (im Gegensatz zu" keine Verknüpfung "), und somit beziehen sich alle Instanzen des Namens auf die gleiche Entität. –

+0

@KerrekSB, sichere Sache. Werde hinzufügen. – SergeyA

0

Wenn wir über den Windows-Compiler sprechen es ist garantiert

https://msdn.microsoft.com/en-us/library/y5f6w579.aspx

Das folgende Beispiel zeigt eine lokale Variable in einer Memberfunktion statisch deklariert. Die statische Variable ist für das gesamte Programm verfügbar. Alle Instanzen des Typs teilen dieselbe Kopie der statischen Variablen.

Sie verwenden ein Beispiel sehr ähnlich zu Ihrem.

Ich weiß nicht über GCC

0

Ja, es ist garantiert. Nun, um die Frage "Jedes Risiko der lokalen statischen Variablen einer Methode zwischen Instanzen zu teilen?" Zu beantworten. es könnte ein bisschen weniger direkt sein. Es kann potentielle Risiken bei der Initialisierung und Verwendung der Variablen geben und diese Risiken sind spezifisch für Variablen, die für die Methode lokal sind (im Gegensatz zu Klassenvariablen).

Für die Initialisierung im Standard ein relevanter Teil ist 6,7/4 [stmt.dcl]:

Dynamische Initialisierung eines variablen Block-scope mit statischen Speichern Dauer (3.7.1) oder Gewinde Speicherdauer (3.7.2) durchgeführt wird die erste Zeit Kontrolle durchläuft seine Erklärung; Eine solche Variable ist , die nach Abschluss ihrer Initialisierung als initialisiert betrachtet wird. Wenn die Initialisierung beendet wird, indem eine Ausnahme ausgelöst wird, ist die Initialisierung nicht abgeschlossen, daher wird es beim nächsten Mal, wenn das Steuerelement die Deklaration eingibt, erneut versucht. Wenn die Steuerung die Deklaration gleichzeitig eingibt, während die Variable initialisiert wird, muss die gleichzeitige Ausführung auf den Abschluss der Initialisierung warten.Wenn das Steuerelement die Deklaration rekursiv erneut eingibt, während die Variable initialisiert wird, ist das Verhalten nicht definiert.

In den einfachen Fällen sollte alles wie erwartet funktionieren. Wenn die Konstruktion und Initialisierung der Variablen komplexer ist, gibt es spezifische Risiken für diesen Fall. Zum Beispiel, wenn der Konstruktor wirft, wird es die Möglichkeit haben, erneut auf den nächsten Anruf zu werfen. Ein anderes Beispiel wäre eine rekursive Initialisierung, bei der es sich um undefiniertes Verhalten handelt.

Ein weiteres mögliches Risiko ist die Durchführung der Methode. Der Compiler muss einen Mechanismus implementieren, um eine konforme Initialisierung der Variablen sicherzustellen. Dies ist implementierungsabhängig und es könnte sehr wohl eine Sperre sein, um zu überprüfen, ob die Variable initialisiert ist, und diese Sperre könnte jedes Mal ausgeführt werden, wenn die Methode aufgerufen wird. Wenn dies geschieht, kann dies die Leistung erheblich beeinträchtigen.

+0

Kein Compiler, der den Wächter wirklich an jedem Eingang in die Funktion sperrt, lohnt sich 2016 als Compiler. – SergeyA

+0

@SergeyA das ist ein sehr guter Punkt und jeder, der die Wahl hat, sollte einen guten Compiler verwenden. Für diejenigen, die in älteren Umgebungen arbeiten müssen, lohnt es sich, die Auswirkungen auf die Leistung zu überprüfen, wenn dies ein kritischer Faktor ist. Zum Beispiel können statische lokale Variablen mit gcc 4.4.7 bei jedem Funktionsaufruf einen Overhead von mehreren CPU-Zyklen einführen. –

+0

Nun, Sie sollten keine Themen ersetzen, oder? Es gibt einen bestimmten (move + branch) Overhead, der mit statischen Variablen verknüpft ist (gab es vom Beginn der Zeit an, niemand bestreitet das). Und die meisten Menschen können damit leben. Sie haben jedoch behauptet, dass die Sperre jedes Mal ausgeführt werden kann, wenn die Methode aufgerufen wird. Dies ist eine ganz andere Sache, mit der die meisten Leute nicht leben können. – SergeyA

1

Nur eine Sache, um die richtige Antwort hinzuzufügen. Wenn Ihre Klasse eine Schablone wäre, würde die Instanz var nur für Objekte desselben Instanziierungstyps verwendet. Also, wenn Sie hatte:

template<typename C> 
class Hello { 
     public: 
     int World(int in) 
     { 
       static int var = 0; // <<<< This thing here. 
       if(in >= 0) { 
         var = in; 
       } else { 
         cout << var << endl; 
       } 
     } 
}; 

Und dann:

Hello<int> A; 
Hello<int> B; 
Hello<unsigned> C; 

A.World(10); 
A.World(-1); 
B.World(-1); 
C.World(-1); 

Dann würde die endgültige Ausgabe „0“ statt „10“, weil die Hello<unsigned> Instanziierung seine eigene Kopie von var haben würde.

+0

Ein wichtiger Vorbehalt! –

Verwandte Themen