Skip to content

La Durata di Archiviazione (Storage Duration)

“Things you used to own, now they own you.” — Chuck Palahniuk, Fight Club

Il ciclo di vita di un oggetto è la serie di stadi che un oggetto C++ attraversa durante la sua esistenza. Tutto ruota attorno all’allocazione e deallocazione della memoria. A differenza di linguaggi con Garbage Collector (come Java o C#), in C++ la gestione delle risorse non è magica: è compito del programmatore plasmare e comprendere la durata degli oggetti (Storage Duration).

Ogni oggetto attraversa queste fasi:

  1. Allocazione della memoria e inizio della storage duration.
  2. Chiamata al costruttore (inizio della lifetime vera e propria).
  3. Utilizzo nel programma.
  4. Chiamata al distruttore (fine della lifetime).
  5. Deallocazione della memoria (fine della storage duration).

Un oggetto automatico viene allocato all’inizio del blocco di codice in cui risiede (il suo scope) e viene deallocato alla fine dello stesso. I parametri delle funzioni e le variabili locali sono oggetti automatici.

void power_up(int amount) {
int local_var = 0;
// amount e local_var sono variabili automatiche.
// Smetteranno di esistere appena la funzione finisce.
}

Un oggetto statico (dichiarato con static o extern al di fuori di una funzione, o come variabile globale) viene allocato all’inizio del programma e deallocato alla fine. La sua esistenza copre l’intero tempo di esecuzione.

L’uso di static in contesti globali impone anche l’Internal Linkage, ovvero rende la variabile inaccessibile dagli altri file sorgenti (translation units) del progetto. Per avere visibilità su tutto il progetto (External Linkage), si usa la keyword extern.

I membri di una classe solitamente muoiono con l’oggetto che li contiene. I membri statici, invece, non sono associati a una singola istanza della classe ma appartengono alla classe in sé, e ne esiste sempre e solo una singola copia condivisa da tutte le istanze. Essi hanno durata di archiviazione statica.

Quando si scrivono programmi concorrenti (multi-thread), le variabili globali mutabili sono fonte di infiniti problemi (race conditions). Se anteponiamo thread_local, creiamo una variabile la cui durata è limitata alla vita del singolo thread, garantendo che ogni thread abbia la propria istanza indipendente e isolata della variabile.

La durata dinamica è quella su cui hai controllo manuale completo: sei tu a dire quando allocare la risorsa e quando distruggerla. Avviene tramite la keyword new per allocare e delete per deallocare.

Da un grande potere derivano immensi problemi:

  • Memory Leaks: Se ti dimentichi di chiamare delete, la memoria non verrà mai restituita al sistema fino al riavvio/chiusura del processo.
  • Use After Free: Se usi un puntatore su cui è già stata chiamata delete, stai leggendo/scrivendo “nel vuoto”. Ciò causa corruzione della memoria e vulnerabilità di sicurezza.