Supponiamo che io sia un insegnante e voglio spiegare ai miei studenti quali sono i vantaggi dell'utilizzo di RAII in C ++ : Ho bisogno di un ottimo esempio, ricco di dettagli, ma è facile da capire.
Quale approccio useresti?
Supponiamo che io sia un insegnante e voglio spiegare ai miei studenti quali sono i vantaggi dell'utilizzo di RAII in C ++ : Ho bisogno di un ottimo esempio, ricco di dettagli, ma è facile da capire.
Quale approccio useresti?
C'è la classica apertura e chiusura di un file. Usando RAII il flusso principale dell'algoritmo sarà chiaro senza ingombrarsi con molta logica try / finally-close che sporca il paesaggio.
Oltre alla chiarezza che fornisce al codice (separando la pulizia dalla logica di base), c'è la sicurezza. Se hai un database, assicurati che le connessioni vengano prese dal pool il più LATE possibile. E tornò alla piscina il più presto possibile. Senza RAII c'è un'alta probabilità che qualcuno possa accidentalmente aggrapparsi a una connessione da qualche parte. Questo aumenta la possibilità che la piscina sia vuota e le cose esploderanno. Su un sistema con un volume utente elevato, questo è serio.
Sicurezza e chiarezza.
EDIT: Oh, quasi dimenticato. Si presta anche molto bene per invertire la pulizia dell'ordine. Come regola generale, in genere si desidera ripulire le cose nell'ordine inverso in cui l'hai ottenuta. Ad esempio, se sei in una banca, apri la porta, quindi apri la cassastrong. Alla fine della giornata, vuoi chiudere la porta della cassastrong prima di chiudere la porta della banca (come una pila). Dal momento che RAII è letteralmente controllato dallo stack, è un adattamento naturale per la pulizia inversa tramite scope.
RAII è così dannatamente elegante. Secondo me è la "risposta" alla pulizia delle risorse. A differenza di un garbage collector è appropriato per più di una semplice memoria. Sfortunatamente non molti programmatori lo capiscono; sia vecchia scuola che nuova scuola.
Penso che un modo per trasmettere la nozione sia con l'esempio. Implementare una classe che richiede alcune risorse che è probabile che non riescano a volte. Aprire un file che potrebbe non esistere o qualcosa di simile. Per prima cosa implementalo senza usare RAII, quindi mostra come tutto il codice di gestione degli errori scompare quando usi RAII in modo sensato.
La ridotta complessità del codice che utilizza RAII dovrebbe rendere i benefici abbastanza ovvi, penso.
Il vantaggio di RAII è in definitiva l'incapsulamento, in quanto una volta che hai creato un oggetto non devi più preoccuparti di cosa farne dopo averlo usato.
Quindi, se hai una classe che apre un handle di file, puoi fare qualsiasi operazione che ti piace su quell'oggetto (che influenza il file sottostante) e quando distruggi l'oggetto, non devi più pensare "devo avere per chiudere l'handle del file "o" il handle del file è ancora chiuso ". È andato, gestito, completamente automaticamente gestito per te. E quella magia succede a causa di RAII.
Quindi puoi confrontare la gestione della memoria manuale in stile C da RAII a quella in cui devi aprire un file, passare il manico a varie funzioni e quindi ricordare di passare l'handle a un funzione close_file (). Puoi confrontarlo con la gestione degli oggetti manuali della raccolta dei rifiuti in stile "caffè", in cui devi creare un oggetto che apre un file, eseguire operazioni sull'oggetto e quindi ricordare per chiamare disporre o avvolgere il tuo oggetto in un blocco using per far girare il metodo dispose - e devi mettere un codice speciale nel tuo finalizzatore per cancellarlo.
E poi puoi mostrare il modo C ++ dove non devi ricordarti di fare nulla, funziona magicamente solo per te, proprio lì e poi (quindi se improvvisamente devi riaprire il file, è non bloccato da un oggetto che è in attesa di essere garbage collection).
PS. Il discorso di Herb Sutter su Build sulle moderne funzionalità C ++ ha una sezione su RAII, a partire da 13 : 50 minuti in cui mostra un confronto tra codice stile C e codice C ++ RAII.
RAII viene utilizzato in diversi punti della libreria standard. È utile vedere esempi chiari usati dallo standard. Buoni esempi includono una qualsiasi delle classi iostream, fstream, sstream, ecc. Anche auto_ptr (o ora unique_ptr) dimostrano RAII per situazioni di memoria.
Leggi altre domande sui tag programming-languages programming-practices c++ learning