Menu
Coddy logo textTech

RAII in C++

Fa parte della sezione Programmazione orientata agli oggetti del percorso C++ di Coddy. Lezione 16 di 104.

RAII (Resource Acquisition Is Initialization) è un idioma fondamentale del C++ in cui la gestione delle risorse è legata alla durata dell'oggetto. L'idea è semplice: acquisisci le risorse nel costruttore e rilasciale nel distruttore.

Quando viene creato un oggetto, acquisisce le risorse di cui ha bisogno. Quando l'oggetto esce dall'ambito, il suo distruttore rilascia automaticamente tali risorse. Questo garantisce la pulizia anche se si verificano eccezioni.

class FileHandler {
    std::FILE* file;
public:
    FileHandler(const char* filename) {
        file = std::fopen(filename, "r");  // Acquisisci la risorsa
    }
    
    ~FileHandler() {
        if (file) std::fclose(file);       // Rilascia la risorsa
    }
};

Con RAII, non dimentichi mai di eseguire la pulizia:

void processFile() {
    FileHandler handler("data.txt");  // Risorsa acquisita
    // Lavora con il file...
    // Se qui viene lanciata un'eccezione, il distruttore viene comunque eseguito!
}   // Risorsa rilasciata automaticamente

I puntatori intelligenti sono l'esempio perfetto di RAII in azione. Un unique_ptr acquisisce la proprietà della memoria heap nel suo costruttore e la elimina nel suo distruttore. Hai già utilizzato RAII senza rendertene conto!

RAII si applica a qualsiasi risorsa: memoria, handle di file, connessioni di rete, mutex o connessioni al database. Incapsulando le risorse negli oggetti, C++ garantisce una pulizia deterministica ed elimina intere categorie di bug, come le perdite di memoria e gli handle pendenti.

challenge icon

Sfida

Facile

Costruiamo un gestore di connessioni che dimostra il RAII gestendo automaticamente il ciclo di vita di connessioni simili a quelle di rete. Quando viene creata una connessione, dovrebbe "aprirsi" e, quando esce dall'ambito, dovrebbe "chiudersi" automaticamente: non serve alcuna pulizia manuale!

Creerai due file per organizzare il codice:

  • Connection.h: definisci una classe Connection che gestisce una risorsa di connessione usando i principi RAII. La classe dovrebbe avere:
    • Un attributo privato connectionId (stringa) per identificare la connessione
    • Un attributo privato isOpen (bool) per tenere traccia dello stato della connessione
    • Un costruttore che accetta un ID di connessione, imposta isOpen su true e stampa "Opening connection: <id>"
    • Un distruttore che controlla se la connessione è aperta, la chiude impostando isOpen su false e stampa "Closing connection: <id>"
    • Un metodo send(string message) che stampa "[<id>] Sending: <message>" se la connessione è aperta
    • Un metodo getId() che restituisce l'ID della connessione
  • main.cpp: dimostra come il RAII garantisce la pulizia automatica leggendo dall'input un ID di connessione e un messaggio. Poi:
    • Crea un ambito usando le parentesi graffe { }
    • All'interno di quell'ambito, crea sullo stack un oggetto Connection con l'ID di input
    • Usa la connessione per inviare il messaggio di input
    • Lascia terminare l'ambito (la connessione dovrebbe chiudersi automaticamente)
    • Dopo l'ambito, stampa "Connection out of scope"

Il bello del RAII è che non devi ricordarti di chiudere la connessione: il distruttore se ne occupa automaticamente quando l'oggetto esce dall'ambito. Questo schema previene le perdite di risorse anche se nel codice succede qualcosa di imprevisto.

Includi il file header in main.cpp usando #include "Connection.h".

Provalo tu

#include <iostream>
#include <string>
#include "Connection.h"

using namespace std;

int main() {
    string connectionId;
    string message;
    
    // Leggi l'input
    cin >> connectionId;
    cin.ignore();
    getline(cin, message);

    // TODO: Crea uno scope usando le parentesi graffe { }
    // All'interno dello scope:
    //   - Crea un oggetto Connection sullo stack con connectionId
    //   - Usa la connessione per inviare il messaggio
    // Lascia terminare lo scope (il distruttore verrà chiamato automaticamente)

    // TODO: Dopo la fine dello scope, stampa "Connection out of scope"

    return 0;
}
quiz iconMettiti alla prova

Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.

Tutte le lezioni di Programmazione orientata agli oggetti

Esercitati da solo: Compilatore C++ online