Scope e lifetime
La dichiarazione di una variabile o di un qualsiasi altro identificatore si
estende dal punto immediatamente successivo la dichiarazione (e prima dell'eventuale
inizializzazione) fino alla fine del blocco di istruzioni in cui e` inserita
(un blocco di istruzioni e` racchiuso sempre tra una coppia di parentesi graffe).
Cio` vuol dire che quella dichiarazione non e` visibile all'esterno di quel
blocco, mentre e` visibile in eventuali blocchi annidati dentro quello dove
la variabile e` dichiarata.
Il seguente schema chiarisce la situazione:
//
Qui X non e` visibile
{
... // Qui X non
e` visibile
int X = 5; // Da ora in poi esiste una
variabile X
... // X e` visibile
gia` prima di =
{ // X e`
visibile anche in questo blocco
...
}
...
} // X ora
non e` piu` visibile
All'interno di uno stesso blocco non e` possibile dichiarare piu` volte lo
stesso identificatore, ma e` possibile ridichiararlo in un blocco annidato;
in tal caso la nuova dichiarazione nasconde quella piu` esterna che ritorna
visibile non appena si esce dal blocco ove l'identificatore viene ridichiarato:
{
... //
qui X non e` ancora visibile
int X = 5;
... //
qui e` visibile int X
{
... //
qui e` visibile int X
char X = 'a'; // ora e` visibile char
X
... //
qui e` visibile char X
} //
qui e` visibile int X
...
}
// X ora non piu` visibile
All'uscita dal blocco piu` interno l'identificatore ridichiarato assume il
valore che aveva prima di essere ridichiarato:
{
...
int X = 5;
cout << X << endl; //
stampa 5
while (--X) { //
riferisce a int X
cout << X << ' '; //
stampa int X
char X = '-';
cout << X << ' '; //
ora stampa char X
}
cout << X << endl; //
stampa di nuovo int X
}
Una dichiarazione eseguita fuori da ogni blocco introduce un identificatore
globale a cui ci si puo` riferire anche con la notazione ::<ID>.
Ad esempio:
int X = 4; //
dichiarazione esterna ad ogni blocco
int main(int, char* []) {
int X = -5, y = 0;
/* ... */
y = ::X; //
a y viene assegnato 4
y = X; //
assegna il valore -5
return 0;
}
Abbiamo appena visto che per assegnare un valore ad una variabile si usa lo
stesso metodo con cui la si inizializza quando viene dichiarata. L'operatore
:: e` detto risolutore di scope e, utilizzato
nel modo appena visto, permette di riferirsi alla dichiarazione globale di un
identificatore.
Ogni variabile oltre a possedere uno scope, ha anche un propria durata (lifetime),
viene creata subito dopo la dichiarazione (e prima dell'inizializzazione! ndr)
e viene distrutta alla fine del blocco dove e` posta la dichiarazione; fanno
eccezione le variabili globali che vengono distrutte alla fine dell'esecuzione
del programma. Da cio` si deduce che le variabili locali (ovvero quelle dichiarate
all'interno di un blocco) vengono create ogni volta che si giunge alla dichiarazione,
e distrutte ogni volta che si esce dal blocco; e` tuttavia possibile evitare
che una variabile locale (dette anche automatiche) venga distrutta all'uscita
dal blocco facendo precedere la dichiarazione dalla keyword static :
void func() {
int x = 5; //
x e` creata e
// distrutta ogni
volta
static int c = 3; // c si
comporta in modo diverso
/* ... */
}
La variabile x viene creata e inizializzata a 5 ogni volta che
func() viene eseguita e viene distrutta alla fine dell'esecuzione
della funzione; la variabile c invece viene creata e inizializzata
una sola volta, quando la funzione viene chiamata la prima volta, e distrutta
solo alla fine del programma. Le variabili statiche conservano sempre l'ultimo
valore che viene assegnato ad esse e servono per realizzare funzioni il cui
comportamento e` legato a computazioni precedenti (all'interno della stessa
esecuzione del programma) oppure per ragioni di efficenza. Infine la keyword
static non modifica lo scope.
|