Ciò di cui sembri catturato è l'inferno specifico di qualcuno che cerca di avere la torta e di mangiarla anch'essa.
RAII ed eccezioni sono progettati per andare di pari passo. RAII è il mezzo con cui non hai per scrivere un sacco di dichiarazioni catch(...)
per fare pulizia. Accadrà automaticamente, naturalmente. E le eccezioni sono l'unico modo per lavorare con gli oggetti RAII, perché i costruttori possono solo riuscire o lanciare (o mettere l'oggetto in uno stato di errore, ma chi lo vuole?).
Un'istruzione catch
può fare una di queste due cose: gestire un errore o una circostanza eccezionale, o eseguire lavori di pulizia. A volte lo fa entrambi, ma ogni dichiarazione catch
esiste per fare almeno uno di questi.
catch(...)
non è in grado di eseguire correttamente la gestione delle eccezioni. Non sai cosa sia l'eccezione; non puoi ottenere informazioni sull'eccezione. Non hai assolutamente altre informazioni oltre al fatto che un'eccezione è stata lanciata da qualcosa all'interno di un certo blocco di codice. L'unica cosa legittima che puoi fare in un blocco del genere è fare pulizia. E questo significa ri-lanciare l'eccezione alla fine della pulizia.
Ciò che RAII ti offre in merito alla gestione delle eccezioni è la pulizia gratuita. Se tutto RAII è incapsulato correttamente, allora tutto sarà pulito correttamente. Non è più necessario avere istruzioni di catch
di pulizia. In tal caso, non c'è motivo di scrivere un'istruzione catch(...)
.
Quindi concordo sul fatto che catch(...)
sia perlopiù malvagio ... provvisoriamente .
Tale disposizione è un uso corretto di RAII. Perché senza di esso, hai bisogno di essere in grado di fare una certa pulizia. Non c'è modo di aggirarlo; devi essere in grado di fare lavori di pulizia. Devi essere in grado di assicurarti che il lancio di un'eccezione lascerà il codice in uno stato ragionevole. E catch(...)
è uno strumento vitale nel farlo.
Non puoi averne uno senza l'altro. Non puoi dire che sia RAII che catch(...)
sono cattivi. Hai bisogno di almeno uno di questi; altrimenti, non sei eccezionalmente sicuro.
Ovviamente, c'è un uso valido, anche se raro, di catch(...)
che nemmeno RAII può bandire: ottenere un exception_ptr
da inoltrare a qualcun altro. In genere attraverso un promise/future
o un'interfaccia simile.
My coworkers says that you should always know what exceptions are to be thrown and that you can always use constructs like:
Il tuo collega è un idiota (o semplicemente terribilmente ignorante). Questo dovrebbe essere immediatamente ovvio a causa della quantità di codice copia e incolla che sta suggerendo di scrivere. la pulizia di ciascuna di queste istruzioni catch sarà esattamente la stessa . Questo è un incubo di manutenzione, per non parlare della leggibilità.
In breve: questo è il problema che RAII è stato creato per risolvere (non che non risolva altri problemi).
Ciò che mi confonde su questa nozione è che è generalmente retrocesso a come la maggior parte delle persone sostiene che RAII è cattivo. Generalmente, l'argomento dice "RAII è male perché devi usare le eccezioni per segnalare il fallimento del costruttore, ma non puoi lanciare eccezioni, perché non è sicuro e devi avere un sacco di dichiarazioni di catch
per pulire tutto. " Che è un argomento rotto perché RAII risolve il problema che la mancanza di RAII crea.
Più che probabile, è contro RAII perché nasconde i dettagli. Le chiamate al distruttore non sono immediatamente visibili sulle variabili automatiche. Quindi ottieni il codice che viene chiamato implicitamente. Alcuni programmatori lo odiano davvero. Apparentemente, al punto in cui pensano di avere il 3% di dichiarazioni dicatch
, tutte cose che fanno la stessa cosa con il codice copia-incolla è un'idea migliore.