Come il C++ gestisce la memoria

Parliamo ancora di memoria, perché fra un po' tratteremo dell'allocazione dinamica della memoria, uno degli argomenti più importanti del C++.
Quando ci arriveremo finalmente vi sarà chiaro perché i puntatori sono così importanti.
Ma prima è bene capire come il C++ gestisce la memoria.

Nel C++ esistono tre modi di gestire la memoria, in base al metodo utilizzato per allocare la memoria: memorizzazione automatica, memorizzazione statica e memorizzazione dinamica.
Visto che di solito si usa il nominativo inglese, facciamolo anche noi: automatic storage, static storage e dynamic storage. Quest'ultimo è anche detto heap.

L'automatic storage è il tipo di gestione della memoria utilizzato dalle comuni variabili.
Sta a significare che una variabile viene creata nel momento in cui il programma si trova all'interno del blocco che la contiene, e viene distrutta nel momento in cui il programma esce da quel blocco:

void funzione1()
{
int varAuto = 10;
}

void funzione2()
{
cout << varAuto; //ERRATO!
}

So che non abbiamo ancora trattato le funzioni, ma il codice qui sopra è di facile comprensione.
Ci sono due funzioni, nella prima viene creata una variabile, mentre nella seconda si tenta di stampare il contenuto di tale variabile. Questo codice non funziona perché la variabile varAuto esiste solo all'interno di funzione1, ed è accessibile solo all'interno di quel blocco. Al di fuori del blocco di funzione1, la variabile cessa di esistere, perciò non possiamo accedervi dall'interno di funzione2.

In questo caso si parla di variabile automatica, e si dice che "la variabile varAuto è locale alla funzione funzione1".
Esiste anche una parola chiave, auto, che fatta precedere da una variabile la rende automatica. Tuttavia non viene usata, se non in rari casi, poiché le variabili sono automatiche di default, e sarebbe ridondante farle precedere dalla parola auto.

Due funzioni possono avere delle variabili con lo stesso nome, proprio perché ogni variabile automatica esiste solo all'interno del blocco in cui è dichiarata:

void funzione1()
{
int varContatore;
}

void funzione2()
{
int varContatore;

varContatore = 93;
}

Quanto appena scritto è legale: infatti quando all'interno di funzione2() utilizziamo la variabile varContatore, ci riferiamo a quella dichiarata all'interno della funzione stessa, e non certo all'omonima variabile all'interno di funzione1().

Lo static storage indica un dato in memoria che è disponibile per tutta l'esecuzione del programma. Per rendere statica una variabile si utilizza la parola chiave static:

void funzione1
{
static int varAuto = 10;
}

void funzione2
{
cout << varAuto; //CORRETTO!
}

Questa versione riveduta del codice precedente è corretta, perché varAuto è stata dichiarata static, il che la rende disponibile anche al di fuori del blocco che la contiene.
Infatti è possibile accedervi anche al di fuori del blocco di funzione1, come mostra l'esempio stesso.

Il dynamic storage invece, viene gestito in modo dinamico dal programma, ed è molto più versatile del metodo utilizzato dalle comuni variabili.

Il campo d'azione di una variabile è detto visibilità della variabile o scope.

Nel prossimo post parleremo dell'allocazione dinamica della memoria.

Nessun commento:

Posta un commento