Zmienne statyczne w funkcjach składowych

158

Czy ktoś może wyjaśnić, jak zmienne statyczne w funkcjach składowych działają w C ++.

Biorąc pod uwagę następującą klasę:

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

Jeśli zadeklaruję wiele wystąpień A, czy wywołanie foo()jednego wystąpienia spowoduje zwiększenie zmiennej statycznej iwe wszystkich wystąpieniach? Czy tylko ten, do którego został wezwany?

Założyłem, że każda instancja będzie miała swoją własną kopię i, ale przeglądanie kodu, który mam, wydaje się wskazywać inaczej.

monofonik
źródło

Odpowiedzi:

169

Ponieważ nie class Ajest klasą szablonową i nie A::foo()jest funkcją szablonową. W programie będzie tylko jedna kopia static int i.

Każda instancja Aobiektu wpłynie na to samo, ia żywotność ipozostanie przez cały program. Aby dodać przykład:

A o1, o2, o3;
o1.foo(); // i = 1
o2.foo(); // i = 2
o3.foo(); // i = 3
o1.foo(); // i = 4
iammilind
źródło
3
Dzięki za dobry przykład! Czy byłby sposób, aby faktycznie osiągnąć coś, co sprawia, że ​​zakres jest static int ispecyficzny dla instancji, tak aby np. o1.foo(); // i = 1I $o2.foo(); // i = 1…?
Stingery
14
Chociaż może to nie być styl, którego szukasz, uczynienie między innymi elementu klasy A danych prywatnych przyniosłoby efekt, który opisujesz. Jeśli obawiasz się konfliktów nazw, możesz dodać przedrostek, taki jak m_wskazujący status i.
Carl Morris,
137

staticSłowo kluczowe ma niestety kilka różnych niezwiązanych ze sobą znaczeń w C ++

  1. Gdy jest używany dla członków danych, oznacza to, że dane są przydzielane w klasie, a nie w instancjach.

  2. W przypadku użycia danych wewnątrz funkcji oznacza to, że dane są przydzielane statycznie, inicjowane przy pierwszym wprowadzeniu bloku i trwają do zakończenia programu. Również zmienna jest widoczna tylko wewnątrz funkcji. Ta szczególna cecha lokalnej statyki jest często używana do implementacji leniwej konstrukcji singletonów.

  3. Gdy jest używana na poziomie jednostki kompilacji (moduł), oznacza to, że zmienna jest podobna do zmiennej globalnej (tj. Jest przydzielana i inicjowana przed mainuruchomieniem i niszczona po mainwyjściu), ale zmienna nie będzie dostępna ani widoczna w innych jednostkach kompilacji .

Położyłem nacisk na tę część, która jest najważniejsza dla każdego zastosowania. Użycie (3) jest nieco odradzane na rzecz nienazwanych przestrzeni nazw, które również pozwalają na nieeksportowane deklaracje klas.

W twoim kodzie staticsłowo kluczowe ma znaczenie numer 2 i nie ma nic wspólnego z klasami lub instancjami ... jest to zmienna funkcji i będzie tylko jedna jej kopia.

Jak słusznie powiedział iammilind , mogłoby jednak istnieć wiele wystąpień tej zmiennej, gdyby funkcja była funkcją szablonu (ponieważ w takim przypadku faktycznie sama funkcja może występować w wielu różnych kopiach w programie). Nawet wtedy, gdy zajęcia i instancje kursu są nieistotne ... zobacz następujący przykład:

#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
źródło
41
+1 za keyword static unfortunately has a few different unrelated meanings in C++:)
iammilind
świat nabiera o wiele większego sensu po przeczytaniu tego, DZIĘKUJĘ
Erin
Podoba mi się sztuczka z szablonami. Nie mogę się doczekać, aby znaleźć wymówkę, aby go użyć.
Tomáš Zato - Przywróć Monikę
Czy ktoś ma odniesienie do „nieco zniechęcenia na rzecz nienazwanych przestrzeni nazw”?
austinmarton
3
@austinmarton: Fraza „Użycie wartości statycznej do wskazania„ jednostki lokalnej dla translacji ”jest przestarzała w C ++. Zamiast tego używaj nienazwanych przestrzeni nazw (8.2.5.1)” jest obecna w języku programowania C ++ w moim wydaniu (10. druk, wrzesień 1999) na stronie 819.
6502
2

Zmienne statyczne wewnątrz funkcji

  • Zmienna statyczna jest tworzona wewnątrz funkcji i jest przechowywana w pamięci statycznej programu, a nie na stosie.

  • Inicjalizacja zmiennej statycznej zostanie wykonana przy pierwszym wywołaniu funkcji.

  • Zmienna statyczna zachowa wartość w wielu wywołaniach funkcji

  • Okres istnienia zmiennej statycznej to Program

wprowadź opis obrazu tutaj

Przykłady

#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;
}

Wynik :

Zmienna statyczna

Wartość zmiennej: 0
Wartość zmiennej: 1
Wartość zmiennej: 2
Wartość zmiennej: 3
Wartość zmiennej: 4

Zmienna automatyczna

Wartość zmiennej: 0
Wartość zmiennej: 0
Wartość zmiennej: 0
Wartość zmiennej: 0
Wartość zmiennej: 0

Saurabh Raoot
źródło
-2

Uproszczona odpowiedź:

Zmienne statyczne, niezależnie od tego, czy są członkami funkcji (bez szablonu), classczy (bez szablonu), zachowują się - technicznie - jak globalna etykieta, której zakres jest ograniczony do classfunkcji lub.

0xbadf00d
źródło
9
Nie. Globale są inicjowane podczas uruchamiania programu, statystyka funkcji jest inicjowana przy pierwszym użyciu. To duża różnica.
6502
Nie sądzę, żeby tak się stało. Jednak i tak powinno to być specyficzne dla kompilatora.
0xbadf00d
2
Wtedy myślisz źle: 3.6.1 w standardzie C ++ mówi, że konstrukcja obiektu o zakresie przestrzeni nazw ze statycznym czasem trwania ma miejsce podczas uruchamiania; 6.7 (4) mówi, że generalnie „... taka zmienna jest inicjalizowana, gdy sterowanie przechodzi przez swoją deklarację po raz pierwszy; taka zmienna jest uważana za zainicjowaną po zakończeniu jej inicjalizacji”. Nawiasem mówiąc, ta inicjalizacja przy pierwszym użyciu jest bardzo przydatna przy implementacji leniwej konstrukcji singletona.
6502
3.7.4: „Stała inicjalizacja (3.6.2) jednostki o zakresie blokowym ze statycznym czasem przechowywania, jeśli ma to zastosowanie, jest wykonywana przed pierwszym wprowadzeniem jej bloku. Dozwolone jest wykonanie wczesnej inicjalizacji innych zmiennych o zakresie blokowym z statyczny lub wątkowy czas trwania przechowywania w tych samych warunkach, w których implementacja może statycznie zainicjować zmienną ze statycznym lub wątkowym czasem trwania w zakresie przestrzeni nazw (3.6.2). W przeciwnym razie taka zmienna jest inicjowana, gdy element sterujący po raz pierwszy przechodzi przez swoją deklarację; "
0xbadf00d
1
Co ciekawe, jednak: 1) w przypadku stałej inicjalizacji nie ma znaczenia dyskusja, czy lokalne statyczne można zainicjować przed wejściem do bloku po raz pierwszy (zmienna jest widoczna tylko wewnątrz bloku, a stała inicjalizacja nie wywołuje skutków ubocznych); 2) w Twoim poście nic nie mówi o ciągłej inicjalizacji; 3) Statyka lokalna jest bardzo przydatna do nieciągłej inicjalizacji, na przykład MyClass& instance(){ static MyClass x("config.ini"); return x; }- poprawna przenośna implementacja do użytku w jednym wątku, ponieważ lokalne statystyki NIE są po prostu globalne, pomimo tego, co mówisz.
6502