Variabili statiche nelle funzioni membro


158

Qualcuno può spiegare come funzionano le variabili statiche nelle funzioni membro in C ++.

Data la seguente classe:

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

Se dichiaro più istanze di A, la chiamata foo()su un'istanza aumenta la variabile statica isu tutte le istanze? O solo quello a cui è stato chiamato?

Supponevo che ogni istanza avrebbe avuto la sua copia di i, ma scorrere un po 'di codice che ho sembra indicare il contrario.

Risposte:


169

Since class Aè una classe non modello ed A::foo()è una funzione non modello. Ci sarà una sola copia static int iall'interno del programma.

Qualsiasi istanza di Aoggetto influirà sullo stesso ie la durata di vita irimarrà per tutto il programma. Per aggiungere un esempio:

A o1, o2, o3;
o1.foo(); // i = 1
o2.foo(); // i = 2
o3.foo(); // i = 3
o1.foo(); // i = 4

3
Grazie per il buon esempio! Ci sarebbe un modo per ottenere effettivamente qualcosa che renda l'ambito static int ispecifico dell'istanza, in modo tale che ad es. o1.foo(); // i = 1E $o2.foo(); // i = 1...?
Stingery

14
Anche se questo potrebbe non essere lo stile che stai cercando, rendere un membro privato di dati di classe A avrebbe l'effetto che stai descrivendo. Se sei preoccupato per i conflitti di nomi, puoi aggiungere un prefisso tale da m_indicare lo stato di i.
Carl Morris,

137

La parola chiave staticsfortunatamente ha alcuni significati non correlati in C ++

  1. Se utilizzato per i membri dei dati, significa che i dati sono allocati nella classe e non nelle istanze.

  2. Se utilizzato per i dati all'interno di una funzione, significa che i dati vengono allocati staticamente, inizializzati la prima volta che il blocco viene inserito e dura fino alla chiusura del programma. Inoltre la variabile è visibile solo all'interno della funzione. Questa caratteristica speciale della statica locale viene spesso utilizzata per implementare la costruzione pigra di singoli.

  3. Se utilizzato a livello di unità di compilazione (modulo) significa che la variabile è come un globale (ovvero allocato e inizializzato prima che mainvenga eseguito e distrutto dopo le mainuscite) ma che la variabile non sarà accessibile o visibile in altre unità di compilazione .

Ho aggiunto un po 'di enfasi alla parte che è più importante per ogni uso. Use (3) è in qualche modo scoraggiato a favore di spazi dei nomi senza nome che consentono anche dichiarazioni di classe non esportate.

Nel tuo codice la staticparola chiave viene utilizzata con il significato numero 2 e non ha nulla a che fare con classi o istanze ... è una variabile della funzione e ne rimarrà solo una copia.

Come giustamente ha detto iammilind, tuttavia, se la funzione fosse una funzione modello, potrebbero esserci più istanze di quella variabile (perché in tal caso la funzione stessa può essere presente in molte copie diverse del programma). Anche in questo caso, naturalmente, le lezioni e le istanze sono irrilevanti ... vedere l'esempio seguente:

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

41
+1 per keyword static unfortunately has a few different unrelated meanings in C++:)
iammilind

il mondo ha molto più senso dopo aver letto questo, GRAZIE
Erin

Mi piace il trucco con i modelli. Non vedo l'ora di trovare una scusa per usarlo.
Tomáš Zato - Ripristina Monica il

Qualcuno ha ottenuto un riferimento per "un po 'scoraggiato a favore di spazi dei nomi senza nome"?
austinmarton,

3
@austinmarton: la frase "L'uso di static per indicare" local to translation unit "è deprecato in C ++. Usa invece spazi dei nomi senza nome (8.2.5.1)" è presente in The C ++ Programming Language nella mia edizione (decima stampa, settembre 1999) a pagina 819.
6502

2

Variabili statiche all'interno delle funzioni

  • La variabile statica viene creata all'interno di una funzione memorizzata nella memoria statica del programma non nello stack.

  • L'inizializzazione della variabile statica verrà eseguita alla prima chiamata della funzione.

  • La variabile statica manterrà il valore in più chiamate di funzione

  • La durata della variabile statica è Programma

inserisci qui la descrizione dell'immagine

Esempi

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

Produzione :

Variabile statica

Valore variabile: 0
Valore variabile: 1
Valore variabile: 2
Valore variabile: 3
Valore variabile: 4

Variabile automatica

Valore variabile: 0
Valore variabile: 0
Valore variabile: 0
Valore variabile: 0
Valore variabile: 0


-2

Risposta semplificata:

Le variabili statiche, indipendentemente dal fatto che siano membri di una funzione (non basata su modelli) classo (non basate su modelli), si comportano - tecnicamente - come un'etichetta globale il cui ambito è limitato alla classfunzione o.


9
No. I globi vengono inizializzati all'avvio del programma, le statistiche delle funzioni vengono inizializzate al primo utilizzo. Questa è una grande differenza.
6502

Non penso che sia quello che succede. Tuttavia, questo dovrebbe essere specifico del compilatore comunque.
0xbadf00d,

2
Quindi pensi in modo sbagliato: 3.6.1 nello standard C ++ impone che la costruzione di oggetti con ambito dello spazio dei nomi con durata dell'archiviazione statica avvenga all'avvio; 6.7 (4) impone che in generale "... tale variabile viene inizializzata la prima volta che il controllo passa attraverso la sua dichiarazione; tale variabile è considerata inizializzata al completamento della sua inizializzazione". A proposito, questa inizializzazione al primo utilizzo è molto utile per implementare la costruzione pigra singleton.
6502

3.7.4: "L'inizializzazione costante (3.6.2) di un'entità con ambito di blocco con durata dell'archiviazione statica, se applicabile, viene eseguita prima dell'inserimento del relativo blocco. Un'implementazione è autorizzata a eseguire l'inizializzazione anticipata di altre variabili con ambito di blocco con durata dell'archiviazione statica o thread nelle stesse condizioni in cui un'implementazione è autorizzata a inizializzare staticamente una variabile con durata dell'archiviazione statica o thread nell'ambito dello spazio dei nomi (3.6.2). In caso contrario, tale variabile viene inizializzata al primo controllo che passa attraverso la sua dichiarazione; "
0xbadf00d,

1
Curiosamente però: 1) per l'inizializzazione costante è irrilevante discutere se è possibile inizializzare una statica locale prima di entrare nel blocco per la prima volta (la variabile è visibile solo all'interno del blocco e l'inizializzazione costante non produce effetti collaterali); 2) nel tuo post non viene detto nulla sull'inizializzazione costante; 3) le statistiche locali sono molto utili per l'inizializzazione non costante come MyClass& instance(){ static MyClass x("config.ini"); return x; }: un'implementazione portatile valida per l'uso a thread singolo esattamente perché le statistiche locali NON sono semplicemente come globali nonostante ciò che dici.
6502
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.