2010-01-29 26 views
11

Lassen Sie uns sagen, ich habe dieses Programm:Statische Variablen in Instanzmethoden

class Foo { 
public: 
    unsigned int bar() { 
     static unsigned int counter = 0; 
     return counter++; 
    } 
}; 

int main() 
{ 
    Foo a; 
    Foo b; 
} 

(Natürlich ist dieses Beispiel macht keinen Sinn, da ich offensichtlich „counter“ als privates Attribut erklären würde, aber es ist nur die zur Veranschaulichung Problem).

Ich würde gerne wissen, wie C++ in einer solchen Situation verhält: Wird die Variable "counter" in der Methode bar() für jede Instanz gleich sein?

Antwort

10

Ja, counter wird für alle Instanzen von Objekten vom Typ Foo in Ihrer ausführbaren Datei freigegeben. Solange Sie sich in einer Einthread-Umgebung befinden, funktioniert es wie erwartet als gemeinsamer Zähler.

In einer Multithread-Umgebung haben Sie interessante Race-Bedingungen zum Debuggen :).

+0

+1 für die Erwähnung von Gefahren in einer Multithread-Umgebung. – Omnifarious

+0

Angenommen, der Compiler behandelt das nicht bereits für Sie. Die Sprachdefinition besteht darin, dass die Variable für alle Aufrufe der Methode konsistent ist. Daher ist es der Compiler-Job, der dies erzwingt, also in Multi-Threaded-Sprachen (nächste Version von C++) ist es der Compiler-Job. In dieser Version kommt es auf die Integration des Compilers mit der Threading-Bibliothek an. gcc hat dies bereits abgedeckt und garantiert, dass der Zugriff auf die statische Variable über mehrere Threads hinweg sicher ist. –

+0

@Martin York: d. H. Statische Variablen in C++ 0x sind garantiert Thread-Local? Wie interessant, und es könnte möglicherweise einige Leute sehr überraschen. Wie ein netter statischer Klasseninstanzzähler. Plötzlich würden Sie stattdessen Instanzen pro Thread zählen. Ich kann nicht glauben, dass sie so etwas ändern würden. Bist du sicher?! – Omnifarious

2

Mit "für jede Instanz gleich sein" meinen Sie, dass es eine Instanz dieser Variablen geben wird, die über jede Klasseninstanz verteilt wird, dann ja, das ist richtig. Alle Instanzen der Klasse verwenden dieselbe Variableninstanz.

Aber denken Sie daran, dass Sie bei Klassenvariablen in vielen Fällen Dinge wie Multithreading berücksichtigen müssen, was ein ganz anderes Thema ist.

1

Von Die C++ Programming Language (2. Auflage), Seite 200, von Bjarne Stroustrup:

Verwenden Sie keine statische außer in [plain] Funktionen (§7.1.2) und Klassen (§10.2.4).

+4

Regeln sind fantastisch. __BUT__ nur, wenn es im richtigen Kontext verwendet wird. Ein nieve Benutzer kann das Zitat zu hart nehmen. Wenn Sie so etwas zitieren möchten, müssen Sie __must__ den vollständigen Kontext einschließen. –

0

Sie müssen nur zwei Dinge erreichen:

  1. Statische Variablen in statischen Bereich des auszuführenden Programms gespeichert sind (die wie die globale Variable gleich ist).
  2. Scope ist durch die allgemeinen Regeln der Klammern begrenzt.Zusätzlich statische Variablen haben interne Verknüpfung.
+0

Lebensdauer ist nicht das Leben des Programms. Es ist von der ersten Verwendung (die niemals sein kann) bis zur Zerstörung (was die umgekehrte Reihenfolge der Erzeugung von statischen Variablen ist). Alos Noten Initialisierung ist gut, da es Teil der Funktion ist nicht die Klasse. –

+0

@niel .. mein schlechtes !! Ich habe das nicht gesehen – sud03r

+0

Der letzte Satz ist über Namespace Scope statische Variablen. Lokale statische Variablen (wie die in der Frage) haben keine Verknüpfung. (Es gibt keine Möglichkeit, sich auf lokale Variablen aus verschiedenen Bereichen zu beziehen. Wie würden Sie sich auf eine in main definierte Variable beziehen? 'Main() :: v' funktioniert beispielsweise nicht). –

1

Ihr Beispiel war ein paar Zeilen weg von etwas, Sie kompilieren und zu testen konnte:

#include <iostream> 
using namespace std; 
class Foo { 
public: 
    unsigned int bar() { 
     static unsigned int counter = 0; 
     return counter++; 
    } 
}; 

int main() 
{ 
    Foo a; 
    Foo b; 

    for (int i=0; i < 10; i++) 
     cout<<i<<". "<<a.bar()<<"/"<<b.bar()<<endl; 
} 

Die Ausgabe sieht wie folgt aus:

0. 1/0 
1. 3/2 
2. 5/4 
3. 7/6 
4. 9/8 
5. 11/10 
6. 13/12 
7. 15/14 
8. 17/16 
9. 19/18 

Also ja, wird der Zähler über geteilt alle Instanzen.

+0

Was amüsant ist, ist, dass Ihre Ausgabe ein perfektes Beispiel dafür ist, wie Sequenzpunkte und Ausführungsreihenfolge funktionieren und zu nicht intuitiven Ergebnissen führen können. – Omnifarious