Perché non dovrei avvolgere ogni blocco in "prova" - "cattura"?


430

Sono sempre stato convinto che se un metodo può generare un'eccezione, è sconsiderato non proteggere questa chiamata con un blocco try significativo.

Ho appena pubblicato " Dovresti SEMPRE concludere le chiamate che possono essere provate, catturare i blocchi. "a questa domanda e mi è stato detto che si trattava di" un consiglio notevolmente negativo "- vorrei capire perché.


4
Se avessi saputo che un metodo avrebbe generato un'eccezione, l'avrei corretto in primo luogo. È perché non so dove e perché il codice genererà eccezioni che le prendo alla fonte (ogni metodo - un generico try-catch). Ad esempio un team mi ha fornito una base di codice con un database precedente. Molte colonne mancavano e venivano catturate solo dopo aver aggiunto il tentativo try catch nel livello SQL. In secondo luogo posso registrare il nome e il messaggio del metodo, per il debug offline, altrimenti non so da dove provenga.
Chakra,

Risposte:


340

Un metodo dovrebbe rilevare un'eccezione solo quando può gestirlo in modo sensato.

Altrimenti, passalo su, nella speranza che un metodo più in alto nello stack di chiamate possa averne senso.

Come altri hanno notato, è buona norma disporre di un gestore di eccezioni non gestito (con registrazione) al livello più alto dello stack di chiamate per garantire che vengano registrati errori irreversibili.


12
Vale anche la pena notare che ci sono costi (in termini di codice generato) per i tryblocchi. C'è una buona discussione nel "Più efficace C ++" di Scott Meyers.
Nick Meyer,

28
In realtà i tryblocchi sono gratuiti in qualsiasi moderno compilatore C, che le informazioni sono datate Nick. Non sono inoltre d'accordo sull'avere un gestore di eccezioni di livello superiore perché perdi le informazioni sulla località (il luogo effettivo in cui l'istruzione non è riuscita).
Blindy,

31
@Blindly: il principale gestore di eccezioni non è lì per gestire l'eccezione, ma in realtà per gridare ad alta voce che c'era un'eccezione non gestita, dare il suo messaggio e terminare il programma in modo grazioso (restituire 1 invece di una chiamata a terminate) . È più un meccanismo di sicurezza. Inoltre, try/catchsono più o meno gratuiti quando non c'è alcuna eccezione. Quando ce n'è uno che si moltiplica, consuma tempo ogni volta che viene lanciato e catturato, quindi una catena di try/catchquel solo ripescaggio non è gratuita.
Matthieu M.

17
Non sono d'accordo che dovresti sempre andare in crash su un'eccezione non rilevata. Il moderno design del software è molto compartimentato, quindi perché dovresti punire il resto dell'applicazione (e, soprattutto, l'utente!) Solo perché si è verificato un errore? Arresto anomalo dell'ultima cosa che si desidera fare, per lo meno provare a fornire all'utente una piccola finestra di codice che consentirà loro di salvare il lavoro anche se non è possibile accedere al resto dell'applicazione.
Kendall Helmstetter Gelner,

21
Kendall: se un'eccezione arriva a un gestore di livello superiore, l'applicazione è per definizione in uno stato indefinito. Sebbene in alcuni casi specifici possa essere utile preservare i dati dell'utente (viene in mente il recupero del documento di Word), il programma non dovrebbe sovrascrivere alcun file o impegnarsi in un database.
Hugh Brackett,

136

Come affermato da Mitch e altri , non dovresti cogliere un'eccezione che non prevedi di gestire in qualche modo. È necessario considerare come l'applicazione gestirà sistematicamente le eccezioni durante la progettazione. Questo di solito porta ad avere livelli di gestione degli errori basati sulle astrazioni - ad esempio, gestisci tutti gli errori relativi a SQL nel tuo codice di accesso ai dati in modo che la parte dell'applicazione che interagisce con gli oggetti di dominio non sia esposta al fatto che lì è un DB sotto il cofano da qualche parte.

Ci sono alcuni odori di codice correlati che si desidera assolutamente evitare oltre all'odore "cattura tutto ovunque" .

  1. "catch, log, rethrow" : se si desidera una registrazione basata su ambito, quindi scrivere una classe che emetta un'istruzione log nel suo distruttore quando lo stack si sta srotolando a causa di un'eccezione (ala std::uncaught_exception()). Tutto quello che devi fare è dichiarare un'istanza di registrazione nell'ambito che ti interessa e, voilà, hai una registrazione e nessuna logica try/ non necessaria catch.

  2. "cattura, lancia tradotto" : questo di solito indica un problema di astrazione. A meno che tu non stia implementando una soluzione federata in cui stai traducendo diverse eccezioni specifiche in una più generica, probabilmente hai uno strato di astrazione non necessario ... e non dire che "potrei averne bisogno domani" .

  3. "catch, cleanup, rethrow" : questo è uno dei miei animali domestici. Se ne riscontri molto, dovresti applicare le tecniche di acquisizione delle risorse è inizializzazione e posizionare la parte di cleanup nel distruttore di un'istanza di oggetto janitor .

Considero il codice disseminato di blocchi try/ catchcome un buon obiettivo per la revisione e il refactoring del codice. Indica che la gestione delle eccezioni non è ben compresa o che il codice è diventato un ameba ed ha un serio bisogno di refactoring.


6
# 1 è nuovo per me. +1 per quello. Inoltre, vorrei notare un'eccezione comune a # 2, che è se stai progettando una libreria spesso vorrai tradurre le eccezioni interne in qualcosa specificato dall'interfaccia della libreria per ridurre l'accoppiamento (questo potrebbe essere ciò che intendi per "soluzione federata", ma non ho familiarità con quel termine).
rmeador,

3
Fondamentalmente quello che hai detto: parashift.com/c++-faq-lite/exceptions.html#faq-17.13
Björn Pollex

1
# 2, dove non è un odore di codice ma ha senso, può essere migliorato mantenendo la vecchia eccezione come nidificata.
Deduplicatore,

1
Per quanto riguarda # 1: std :: uncaught_exception () ti dice che c'è un'eccezione non rilevata in volo, ma AFAIK solo una clausola catch () ti consente di determinare quale sia effettivamente quell'eccezione. Pertanto, mentre è possibile registrare il fatto che si sta uscendo da un ambito a causa di un'eccezione non rilevata, solo un try / catch accluso consente di registrare tutti i dettagli. Corretta?
Jeremy,

@Jeremy - hai ragione. Di solito registro i dettagli dell'eccezione quando gestisco l'eccezione. Avere una traccia dei frame intermedi è molto utile. In genere è necessario registrare l'identificatore del thread o un contesto identificativo e correlare le righe del registro. Ho usato una Loggerclasse simile a log4j.Loggerquella che include l'ID thread in ogni riga del log e ho emesso un avviso nel distruttore quando era attiva un'eccezione.
D.Shawley,

48

Perché la domanda successiva è "Ho riscontrato un'eccezione, cosa devo fare dopo?" Cosa farai? Se non fai nulla - questo è nascondere l'errore e il programma potrebbe "semplicemente non funzionare" senza alcuna possibilità di trovare quello che è successo. Devi capire esattamente cosa farai una volta catturata l'eccezione e catturare solo se lo sai.


29

Non è necessario coprire ogni blocco con i tentativi di cattura poiché un tentativo di cattura può ancora rilevare eccezioni non gestite generate nelle funzioni più in basso nello stack di chiamate. Quindi, anziché avere una funzione try-catch in ogni funzione, puoi averne una alla logica di livello superiore della tua applicazione. Ad esempio, potrebbe esserci una SaveDocument()routine di livello superiore, che chiama molti metodi che chiamano altri metodi, ecc. Questi sotto-metodi non hanno bisogno dei propri tentativi di cattura, perché se lanciano, sono ancora catturati dalla SaveDocument()cattura.

Questo è utile per tre motivi: è utile perché hai un unico posto per segnalare un errore: i SaveDocument()blocchi di cattura. Non è necessario ripeterlo in tutti i metodi secondari, ed è comunque quello che vuoi: un unico posto per fornire all'utente una diagnostica utile su qualcosa che è andato storto.

Due, il salvataggio viene annullato ogni volta che viene generata un'eccezione. Con ogni sub-metodo di prova-catching, se viene generata un'eccezione, si arriva a blocco catch che di metodo, foglie di esecuzione della funzione, e prosegue attraverso SaveDocument(). Se qualcosa è già andato storto, probabilmente vorrai fermarti lì.

Tre, tutti i tuoi metodi secondari possono presupporre che ogni chiamata abbia esito positivo . Se una chiamata ha esito negativo, l'esecuzione salterà al blocco catch e il codice successivo non verrà mai eseguito. Questo può rendere il tuo codice molto più pulito. Ad esempio, ecco i codici di errore:

int ret = SaveFirstSection();

if (ret == FAILED)
{
    /* some diagnostic */
    return;
}

ret = SaveSecondSection();

if (ret == FAILED)
{
    /* some diagnostic */
    return;
}

ret = SaveThirdSection();

if (ret == FAILED)
{
    /* some diagnostic */
    return;
}

Ecco come potrebbe essere scritto con eccezioni:

// these throw if failed, caught in SaveDocument's catch
SaveFirstSection();
SaveSecondSection();
SaveThirdSection();

Ora è molto più chiaro cosa sta succedendo.

Nota: il codice sicuro di eccezione può essere più complicato da scrivere in altri modi: non si vuole perdere la memoria se viene generata un'eccezione. Assicurati di conoscere RAII , i contenitori STL, i puntatori intelligenti e altri oggetti che liberano le loro risorse nei distruttori, poiché gli oggetti vengono sempre distrutti prima delle eccezioni.


2
Splendidi esempi. Sì, cattura il più in alto possibile, in unità logiche, come ad esempio in alcune operazioni "transazionali" come un caricamento / salvataggio / ecc. Sembra niente di peggio che il codice condito con ripetitivo, ridondante try- catchblocchi che tentano di bandiera ogni leggermente diverso permutazione di qualche errore con un messaggio leggermente diverso, quando in realtà dovrebbero tutti finiscono lo stesso: fallimento transazione o programma e uscire! Se si verifica un errore degno di eccezione, scommetto che la maggior parte degli utenti vuole solo salvare ciò che può o, almeno, essere lasciato solo senza dover gestire 10 livelli di messaggio al riguardo.
underscore_d

Volevo solo dire che questa è una delle migliori spiegazioni "lancia presto, cattura tardi" che io abbia mai letto: concisa e gli esempi illustrano perfettamente i tuoi punti. Grazie!
corderazo00,

27

Herb Sutter ha scritto su questo problema qui . Sicuramente vale la pena leggere.
Un teaser:

"Scrivere un codice sicuro per le eccezioni è fondamentalmente scrivere" provare "e" catturare "nei posti corretti." Discutere.

Detto senza mezzi termini, tale affermazione riflette un fondamentale fraintendimento della sicurezza delle eccezioni. Le eccezioni sono solo un'altra forma di segnalazione degli errori e sappiamo sicuramente che la scrittura di un codice sicuro non riguarda solo dove controllare i codici di ritorno e gestire le condizioni di errore.

In realtà, si scopre che la sicurezza delle eccezioni riguarda raramente la scrittura di "prova" e "cattura" - e più raramente è meglio. Inoltre, non dimenticare mai che la sicurezza delle eccezioni influisce sulla progettazione di un codice; non è mai solo un ripensamento che può essere adattato con qualche dichiarazione di cattura in più come per il condimento.


15

Come indicato in altre risposte, dovresti prendere un'eccezione solo se riesci a fare una sorta di ragionevole gestione degli errori per questo.

Ad esempio, nella domanda che ha generato la tua domanda, l'interrogante chiede se è sicuro ignorare le eccezioni per un lexical_castda un numero intero a una stringa. Un cast del genere non dovrebbe mai fallire. Se fallisce, qualcosa è andato storto nel programma. Cosa potresti eventualmente fare per recuperare in quella situazione? Probabilmente è meglio lasciare morire il programma, poiché è in uno stato di cui non ci si può fidare. Quindi non gestire l'eccezione può essere la cosa più sicura da fare.


12

Se gestisci sempre immediatamente le eccezioni nel chiamante di un metodo che può generare un'eccezione, allora le eccezioni diventano inutili e faresti meglio a usare i codici di errore.

L'intero punto delle eccezioni è che non è necessario gestirle in tutti i metodi della catena di chiamate.


9

Il miglior consiglio che ho sentito è che dovresti sempre rilevare eccezioni solo nei punti in cui puoi fare sensatamente qualcosa riguardo alla condizione eccezionale, e che "catturare, accedere e rilasciare" non è una buona strategia (se occasionalmente inevitabile nelle biblioteche).


2
@KeithB: la considero una seconda strategia migliore. È meglio se riesci a ottenere il registro scritto in un altro modo.
David Thornley,

1
@KeithB: è una strategia "migliore di niente in una libreria". "Cattura, registra, gestisci correttamente" è meglio dove possibile. (Sì, lo so che non è sempre possibile.)
Donal Fellows

6

Concordo con la direzione di base della tua domanda per gestire quante più eccezioni possibili al livello più basso.

Alcune delle risposte esistenti dicono "Non è necessario gestire l'eccezione. Qualcun altro lo farà nello stack." Per la mia esperienza è una brutta scusa per non pensare alla gestione delle eccezioni nel pezzo di codice attualmente sviluppato, rendendo l'eccezione gestire il problema di qualcun altro o in seguito.

Questo problema cresce in modo drammatico nello sviluppo distribuito, dove potrebbe essere necessario chiamare un metodo implementato da un collega. E poi devi ispezionare una catena nidificata di chiamate di metodo per scoprire perché ti sta gettando un'eccezione, che avrebbe potuto essere gestita molto più facilmente con il metodo nidificato più profondo.


5

Il consiglio che il mio professore di informatica mi ha dato una volta era: "Usa i blocchi Try and Catch solo quando non è possibile gestire l'errore usando mezzi standard".

Ad esempio, ci ha detto che se un programma ha riscontrato un problema serio in un luogo in cui non è possibile fare qualcosa del tipo:

int f()
{
    // Do stuff

    if (condition == false)
        return -1;
    return 0;
}

int condition = f();

if (f != 0)
{
    // handle error
}

Quindi dovresti usare try, catch blocks. Sebbene sia possibile utilizzare le eccezioni per gestirlo, in genere non è consigliabile poiché le eccezioni sono costose in termini di prestazioni.


7
Questa è una strategia, ma molte persone raccomandano di non restituire mai codici di errore o stati di errore / successo dalle funzioni, usando invece le eccezioni. La gestione degli errori basata sulle eccezioni è spesso più facile da leggere rispetto al codice basato sul codice di errore. (Vedi la risposta di AshleysBrain a questa domanda per un esempio.) Inoltre, ricorda sempre che molti professori di informatica hanno pochissima esperienza nella scrittura di codice reale.
Kristopher Johnson,

1
-1 @Sagelika La tua risposta consiste nell'evitare le eccezioni, quindi non c'è bisogno di try-catch.
Vicente Botet Escriba,

3
@Kristopher: Altri grandi svantaggi del codice di ritorno è che è davvero facile dimenticare di controllare un codice di ritorno, e subito dopo la chiamata non è necessariamente il posto migliore per gestire il problema.
David Thornley,

eh, dipende, ma in molti casi (mettendo da parte le persone che lanciano quando non dovrebbero davvero), le eccezioni sono superiori ai codici di ritorno per così tanti motivi. nella maggior parte dei casi, l'idea che le eccezioni siano dannose per le prestazioni è una grande [citazione necessaria]
underscore_d

3

Se si desidera testare il risultato di ogni funzione, utilizzare i codici di ritorno.

Lo scopo di Eccezioni è di poter testare i risultati MENO spesso. L'idea è quella di separare condizioni eccezionali (insolite, più rare) dal tuo codice più ordinario. Ciò mantiene il codice ordinario più pulito e semplice, ma comunque in grado di gestire quelle condizioni eccezionali.

Nel codice ben progettato potrebbero essere lanciate funzioni più profonde e potrebbero catturare funzioni più elevate. Ma la chiave è che molte funzioni "intermedie" saranno libere dall'onere di gestire condizioni eccezionali. Devono solo essere "eccezionalmente sicuri", il che non significa che debbano catturare.


2

Vorrei aggiungere a questa discussione che, dal C ++ 11 , ha molto senso, fintanto che ogni catchblocco rethrowè l'eccezione fino al punto in cui può / dovrebbe essere gestito. In questo modo è possibile generare un backtrace . Ritengo pertanto che i precedenti pareri siano in parte obsoleti.

Usa std::nested_exceptionestd::throw_with_nested

È descritto su StackOverflow qui e qui come raggiungere questo obiettivo.

Dato che puoi farlo con qualsiasi classe di eccezione derivata, puoi aggiungere molte informazioni a tale backtrace! Puoi anche dare un'occhiata al mio MWE su GitHub , dove un backtrace sarebbe simile a questo:

Library API: Exception caught in function 'api_function'
Backtrace:
~/Git/mwe-cpp-exception/src/detail/Library.cpp:17 : library_function failed
~/Git/mwe-cpp-exception/src/detail/Library.cpp:13 : could not open file "nonexistent.txt"

2

Mi è stata data l '"opportunità" di salvare diversi progetti e i dirigenti hanno sostituito l'intero team di sviluppo perché l'app aveva troppi errori e gli utenti erano stanchi dei problemi e del run-around. Tutte queste basi di codice avevano una gestione centralizzata degli errori a livello di app, come descrive la risposta più votata. Se questa risposta è la migliore pratica, perché non ha funzionato e ha permesso al precedente team di sviluppo di risolvere i problemi? Forse a volte non funziona? Le risposte sopra non menzionano il tempo impiegato dagli sviluppatori per risolvere singoli problemi. Se il tempo per risolvere i problemi è la metrica chiave, la strumentazione del codice con i blocchi try..catch è una pratica migliore.

In che modo il mio team ha risolto i problemi senza modificare in modo significativo l'interfaccia utente? Semplice, ogni metodo è stato strumentato con try..catch bloccato e tutto è stato registrato nel punto di errore con il nome del metodo, i valori dei parametri del metodo concatenati in una stringa passata insieme al messaggio di errore, il messaggio di errore, il nome dell'app, la data, e versione. Con queste informazioni gli sviluppatori possono eseguire analisi sugli errori per identificare l'eccezione che si verifica di più! O lo spazio dei nomi con il maggior numero di errori. Può anche confermare che un errore che si verifica in un modulo è gestito correttamente e non causato da molteplici motivi.

Un altro vantaggio di questo è che gli sviluppatori possono impostare un punto di interruzione nel metodo di registrazione degli errori e con un punto di interruzione e un singolo clic del pulsante di debug "Esci", sono nel metodo che ha avuto esito negativo con l'accesso completo all'effettivo oggetti nel punto di guasto, comodamente disponibili nella finestra immediata. Rende molto semplice il debug e consente di trascinare indietro l'esecuzione del metodo per duplicare il problema e trovare la riga esatta. La gestione centralizzata delle eccezioni consente a uno sviluppatore di replicare un'eccezione in 30 secondi? No.

L'affermazione "Un metodo dovrebbe rilevare un'eccezione solo quando è in grado di gestirlo in modo sensato". Ciò implica che gli sviluppatori possono prevedere o riscontreranno tutti gli errori che possono verificarsi prima del rilascio. Se questo fosse vero ai massimi livelli, il gestore delle eccezioni delle app non sarebbe necessario e non ci sarebbe mercato per la ricerca elastica e il logstash.

Questo approccio consente inoltre agli sviluppatori di trovare e risolvere problemi intermittenti nella produzione! Vorresti eseguire il debug senza un debugger in produzione? O preferiresti ricevere chiamate e ricevere e-mail da utenti sconvolti? Ciò consente di risolvere i problemi prima che chiunque altro lo sappia e senza dover inviare e-mail, messaggistica istantanea o Slack con il supporto poiché tutto ciò che è necessario per risolvere il problema è proprio lì. Il 95% dei problemi non deve mai essere riprodotto.

Per funzionare correttamente, deve essere combinato con una registrazione centralizzata in grado di acquisire lo spazio dei nomi / modulo, il nome della classe, il metodo, gli input e il messaggio di errore e archiviare in un database in modo che possa essere aggregato per evidenziare quale metodo fallisce di più in modo che possa essere risolto per primo.

A volte gli sviluppatori scelgono di lanciare eccezioni nello stack da un blocco catch ma questo approccio è 100 volte più lento del normale codice che non genera. È preferibile catturare e rilasciare con la registrazione.

Questa tecnica è stata utilizzata per stabilizzare rapidamente un'app che falliva ogni ora per la maggior parte degli utenti in un'azienda Fortune 500 sviluppata da 12 sviluppatori in 2 anni. Utilizzando queste 3000 diverse eccezioni sono state identificate, risolte, testate e implementate in 4 mesi. Questo fa una media di una correzione ogni 15 minuti in media per 4 mesi.

Sono d'accordo che non è divertente digitare tutto il necessario per strumentare il codice e preferisco non guardare il codice ripetitivo, ma l'aggiunta di 4 righe di codice a ciascun metodo vale la pena nel lungo periodo.


1
Avvolgere ogni blocco sembra eccessivo. Rende rapidamente il tuo codice gonfio e doloroso da leggere. La registrazione di una stack stack da un'eccezione a livelli più alti mostra dove si è verificato il problema e che, in generale, con l'errore stesso sono generalmente sufficienti informazioni per continuare. Sarei curioso di sapere dove non lo hai trovato. Solo così posso acquisire l'esperienza di qualcun altro.
user441521

1
"Le eccezioni sono da 100 a 1000 volte più lente del codice normale e non dovrebbero mai essere riproposte" - questa affermazione non è vera sulla maggior parte dei compilatori e dell'hardware moderni.
Mitch Wheat,

Sembra eccessivo e richiede un po 'di digitazione, ma è l'unico modo per eseguire analisi sulle eccezioni per trovare e correggere prima gli errori più grandi, inclusi gli errori intermittenti nella produzione. Il blocco catch gestisce errori specifici, se necessario, e ha una sola riga di codice che registra.
user2502917

No, le eccezioni sono molto lente. L'alternativa è codici di ritorno, oggetti o variabili. Vedi questo post di overflow dello stack ... "le eccezioni sono almeno 30.000 volte più lente dei codici di ritorno" stackoverflow.com/questions/891217/…
user2502917

1

Oltre ai consigli di cui sopra, personalmente uso alcuni try + catch + throw; per il seguente motivo:

  1. Al confine di un altro programmatore, uso try + catch + throw nel codice scritto da me stesso, prima che l'eccezione venga lanciata al chiamante che è scritta da altri, questo mi dà la possibilità di sapere alcune condizioni di errore verificatesi nel mio codice e questo posto è molto più vicino al codice che inizialmente genera l'eccezione, più si avvicina, più è facile trovarne il motivo.
  2. Al limite dei moduli, sebbene moduli diversi possano essere scritti la mia stessa persona.
  3. Scopo di apprendimento + debug, in questo caso utilizzo catch (...) in C ++ e catch (Exception ex) in C #, per C ++, la libreria standard non genera troppe eccezioni, quindi questo caso è raro in C ++. Ma posto comune in C #, C # ha una libreria enorme e una gerarchia di eccezioni matura, il codice della libreria C # genera tonnellate di eccezioni, in teoria io (e te) dovreste conoscere ogni eccezione dalla funzione che avete chiamato e conoscere il motivo / caso per cui queste eccezioni vengono lanciate e sanno come gestirle (passarle o catturarle e gestirle sul posto con grazia). Sfortunatamente in realtà è molto difficile sapere tutto sulle potenziali eccezioni prima di scrivere una riga di codice. Quindi prendo tutto e lascio che il mio codice parli ad alta voce accedendo (nell'ambiente del prodotto) / affermando la finestra di dialogo (nell'ambiente di sviluppo) quando si verifica davvero un'eccezione. In questo modo aggiungo progressivamente il codice di gestione delle eccezioni. So che si confonde con buoni consigli, ma in realtà funziona per me e non conosco alcun modo migliore per questo problema.

1

Mi sento in dovere di aggiungere un'altra risposta, sebbene la risposta di Mike Wheat riassuma piuttosto bene i punti principali. Ci penso così. Quando hai metodi che fanno più cose stai moltiplicando la complessità, non aggiungendola.

In altre parole, un metodo racchiuso in una modalità try ha due possibili esiti. Hai il risultato di non eccezione e il risultato di eccezione. Quando hai a che fare con molti metodi, esponenzialmente esplode oltre ogni comprensione.

Esponenzialmente perché se ogni metodo si dirama in due modi diversi, ogni volta che chiami un altro metodo stai quadrando il numero precedente di potenziali esiti. Quando hai chiamato cinque metodi hai almeno 256 possibili esiti. Confronta questo con no fare un tentativo / cattura in ogni singolo metodo e hai solo un percorso da seguire.

Fondamentalmente è così che lo guardo. Potresti essere tentato di sostenere che qualsiasi tipo di ramificazione fa la stessa cosa, ma try / catch è un caso speciale perché lo stato dell'applicazione in pratica diventa indefinito.

Quindi in breve, provare / catturare rende il codice molto più difficile da comprendere.


-2

Non è necessario coprire ogni parte del codice all'interno try-catch. L'uso principale del try-catchblocco è la gestione degli errori e ha ottenuto bug / eccezioni nel programma. Alcuni usi di try-catch-

  1. Puoi usare questo blocco dove vuoi gestire un'eccezione o semplicemente puoi dire che il blocco di codice scritto può generare un'eccezione.
  2. Se si desidera disporre gli oggetti immediatamente dopo il loro utilizzo, è possibile utilizzare il try-catchblocco.

1
"Se vuoi smaltire i tuoi oggetti immediatamente dopo il loro utilizzo, puoi usare il blocco try-catch." Intendevi questo per promuovere RAII / durata minima dell'oggetto? Se è così, beh, try/ catchè completamente separato / ortogonale da quello. Se vuoi disporre oggetti in un ambito più piccolo, puoi semplicemente aprirne uno nuovo { Block likeThis; /* <- that object is destroyed here -> */ }- non è necessario avvolgerlo in try/ a catchmeno che tu non abbia effettivamente bisogno di catchqualcosa, ovviamente.
underscore_d

# 2 - Smaltire oggetti (che sono stati creati manualmente) nell'eccezione mi sembra strano, questo può essere utile in alcune lingue senza dubbio, ma generalmente lo fai in un tentativo / finalmente "all'interno del blocco try / tranne", e non in particolare nel blocco di eccezione stesso, poiché l'oggetto stesso potrebbe essere stato la causa dell'eccezione in primo luogo e quindi causare un'altra eccezione e potenzialmente un arresto anomalo.
TS
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.