Domanda

Se una variabile viene dichiarata come static nell'ambito di una funzione, viene inizializzata una sola volta e mantiene il suo valore tra le chiamate di funzione. Qual è esattamente la sua vita? Quando vengono chiamati il ??suo costruttore e distruttore?

void foo() 
{ 
    static string plonk = "When will I die?";
}
È stato utile?

Soluzione

La durata della variabile statica inizia la prima volta [0] il flusso del programma incontra la dichiarazione e termina al termine del programma. Ciò significa che il tempo di esecuzione deve eseguire alcuni libri per poterlo distruggere solo se è stato effettivamente costruito.

Inoltre, poiché lo standard afferma che i distruttori di oggetti statici devono funzionare nell'ordine inverso rispetto al completamento della loro costruzione [1] , e l'ordine di costruzione può dipendere dalla specifica esecuzione del programma , l'ordine di costruzione deve essere preso in considerazione.

Esempio

struct emitter {
    string str;
    emitter(const string& s) : str(s) { cout << "Created " << str << endl; }
    ~emitter() { cout << "Destroyed " << str << endl; }
};

void foo(bool skip_first) 
{
    if (!skip_first)
        static emitter a("in if");
    static emitter b("in foo");
}

int main(int argc, char*[])
{
    foo(argc != 2);
    if (argc == 3)
        foo(false);
}

Output:

  

C: > Sample.exe
  Creato in foo
  Distrutto a piè di pagina

     

C: > sample.exe 1
  Creato in se
  Creato in foo
  Distrutto nel foo
  Distrutto in se

     

C: > sample.exe 1 2
  Creato in foo
  Creato in se
  Distrutto in se
  Distrutto a piè di pagina

[0] Poiché C++98 [2] non ha alcun riferimento a più thread su come ciò si comporterà in un multi- l'ambiente thread non è specificato e può essere problematico come Roddy menziona.

[1] C ++ 98 sezione 3.6.3.1 [basic.start.term]

[2] In C ++ 11 le statistiche sono inizializzate in modo thread-safe, questo è anche noto come Magic Statics .

Altri suggerimenti

Motti ha ragione sull'ordine, ma ci sono alcune altre cose da considerare:

I compilatori utilizzano in genere una variabile di flag nascosta per indicare se le statistiche locali sono già state inizializzate e questo flag viene controllato su ogni voce della funzione. Ovviamente si tratta di un piccolo successo in termini di prestazioni, ma ciò che più preoccupa è che questo flag non è garantito per essere thread-safe.

Se hai una statica locale come sopra, e foo viene chiamato da più thread, potresti avere condizioni di competizione che causano l'inizializzazione errata di plonk o anche più volte. Inoltre, in questo caso plonk potrebbe essere distrutto da un thread diverso da quello che lo ha costruito.

Nonostante ciò che dice lo standard, sarei molto cauto sull'ordine reale di distruzione statica locale, perché è possibile che tu possa inconsapevolmente fare affidamento su una staticità ancora valida dopo che è stata distrutta, e questo è davvero difficile da rintracciare giù.

Le spiegazioni esistenti non sono realmente complete senza la regola effettiva dello Standard, trovata in 6.7:

  

L'inizializzazione zero di tutte le variabili con ambito di blocco con durata dell'archiviazione statica o durata dell'archiviazione del thread viene eseguita prima di qualsiasi altra inizializzazione. L'inizializzazione costante di un'entità con ambito di blocco con durata di memorizzazione statica, se applicabile, viene eseguita prima che il blocco venga immesso per la prima volta. Un'implementazione può eseguire l'inizializzazione anticipata di altre variabili con ambito di blocco con durata dell'archiviazione statica o thread nelle stesse condizioni in cui è consentita un'implementazione per inizializzare staticamente una variabile con durata dell'archiviazione statica o thread nell'ambito dello spazio dei nomi. Altrimenti una variabile del genere viene inizializzata la prima volta che il controllo passa attraverso la sua dichiarazione; tale variabile è considerata inizializzata al completamento della sua inizializzazione. Se l'inizializzazione termina generando un'eccezione, l'inizializzazione   non è completo, quindi verrà riprovato la prossima volta che il controllo entra nella dichiarazione. Se il controllo inserisce la dichiarazione contemporaneamente mentre la variabile viene inizializzata, l'esecuzione simultanea deve attendere il completamento dell'inizializzazione. Se il controllo reinserisce la dichiarazione in modo ricorsivo durante l'inizializzazione della variabile, il comportamento non è definito.

FWIW, Codegear C ++ Builder non si distrugge nell'ordine previsto secondo lo standard.

C:\> sample.exe 1 2
Created in foo
Created in if
Destroyed in foo
Destroyed in if

... che è un altro motivo per non fare affidamento sull'ordine di distruzione!

Le variabili statiche entrano in gioco una volta che inizia l'esecuzione del programma e rimangono disponibili fino al termine dell'esecuzione del programma.

Le variabili statiche vengono create nel Segmento di dati della memoria .

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top