Eccezioni come affermazioni o come errori?


10

Sono un programmatore professionista C e un programmatore hobbista Obj-C (OS X). Di recente sono stato tentato di espandermi in C ++, a causa della sua sintassi molto ricca.

Finora il codice non ho trattato molto delle eccezioni. Objective-C li ha, ma la politica di Apple è abbastanza rigida:

Importante È necessario riservare l'uso di eccezioni per la programmazione o errori di runtime imprevisti come l'accesso alla raccolta fuori limite, i tentativi di mutare oggetti immutabili, l'invio di un messaggio non valido e la perdita della connessione al server di finestre.

Il C ++ sembra preferire l'uso delle eccezioni più spesso. Ad esempio, l'esempio di Wikipedia su RAII genera un'eccezione se non è possibile aprire un file. Objective-C avrebbe return nilun errore inviato da un parametro out. In particolare, sembra che std :: ofstream possa essere impostato in entrambi i modi.

Qui sui programmatori ho trovato diverse risposte che proclamano di usare le eccezioni anziché i codici di errore o di non usare affatto le eccezioni . I primi sembrano più diffusi.

Non ho trovato nessuno che fa uno studio obiettivo per C ++. Mi sembra che, dato che i puntatori sono rari, dovrei scegliere dei flag di errore interni se scelgo di evitare le eccezioni. Sarà troppo fastidioso da gestire o forse funzionerà anche meglio delle eccezioni? Un confronto di entrambi i casi sarebbe la risposta migliore.

Edit: Anche se non del tutto pertinente, forse è meglio chiarire che cosa nilè. Tecnicamente è lo stesso di NULL, ma il fatto è che va bene inviare un messaggio a nil. Quindi puoi fare qualcosa del genere

NSError *err = nil;
id obj = [NSFileHandle fileHandleForReadingFromURL:myurl error:&err];

[obj retain];

anche se la prima chiamata è tornata nil. E come non si fa mai *objin Obj-C, non c'è rischio di una dereferenza del puntatore NULL.


Imho, sarebbe meglio se mostrassi un pezzo di codice Obiettivo C come lavori con gli errori lì. Sembra che la gente stia parlando di qualcosa di diverso da quello che stai chiedendo.
Gangnus,

In un certo senso, sto cercando una giustificazione per l'utilizzo delle eccezioni. Dato che ho idea di come siano implementate, so quanto possono essere costose. Ma immagino che se riesco a ottenere una discussione abbastanza valida per il loro uso, andrò in quel modo.
Per Johansson,

Sembra che per C ++ sia necessaria una giustificazione per non usarli. Secondo le reazioni qui.
Gangnus,

2
Forse, ma finora non c'è stato nessuno che spiegasse perché sono migliori (tranne rispetto ai codici di errore). Non mi piace il concetto di usare le eccezioni per cose che non sono eccezionali, ma è più istintivo che basato sui fatti.
Per Johansson,

"Non mi piace ... usare le eccezioni per cose che non sono eccezionali" - concordano.
Gangnus,

Risposte:


1

Il C ++ sembra preferire l'uso delle eccezioni più spesso.

Vorrei suggerire in realtà meno di Objective-C per alcuni aspetti perché la libreria standard C ++ non genererebbe generalmente errori del programmatore come l'accesso fuori limite di una sequenza ad accesso casuale nella sua forma di progettazione del caso più comune (in operator[], cioè) o cercando di dereferenziare un iteratore non valido. Il linguaggio non si basa sull'accesso a un array fuori limite, sulla dereferenziazione di un puntatore nullo o su qualsiasi cosa di questo tipo.

Prendere gli errori del programmatore in gran parte fuori dall'equazione di gestione delle eccezioni in realtà elimina una categoria molto ampia di errori a cui spesso rispondono altre lingue throwing. Il C ++ tende a assert(che non viene compilato in build di rilascio / produzione, solo build di debug) o semplicemente in errore in questi casi, probabilmente in parte perché il linguaggio non vuole imporre il costo di tali controlli di runtime come sarebbe necessario per rilevare tali errori del programmatore, a meno che il programmatore non voglia specificamente pagare i costi scrivendo il codice che esegue tali controlli da solo.

Sutter incoraggia persino a evitare eccezioni in tali casi negli standard di codifica C ++:

Lo svantaggio principale dell'utilizzo di un'eccezione per segnalare un errore di programmazione è che non si desidera realmente che si verifichi lo svolgersi dello stack quando si desidera che il debugger si avvii sulla riga esatta in cui è stata rilevata la violazione, con lo stato della riga intatto. In breve: ci sono errori che sai che potrebbero accadere (vedi articoli da 69 a 75). Per tutto ciò che non dovrebbe, ed è colpa del programmatore se lo fa, c'è assert.

Quella regola non è necessariamente fissata nella pietra. In alcuni casi più critici, potrebbe essere preferibile usare, diciamo, wrapper e uno standard di codifica che registri in modo uniforme dove si verificano errori del programmatore e throwin presenza di errori del programmatore come cercare di deferire qualcosa di non valido o accedervi senza limiti, perché potrebbe essere troppo costoso non riuscire a recuperare in quei casi se il software ha una possibilità. Ma nel complesso, l'uso più comune della lingua tende a non gettare contro gli errori del programmatore.

Eccezioni esterne

Dove vedo le eccezioni incoraggiate il più delle volte in C ++ (secondo il comitato standard, ad esempio) è per "eccezioni esterne", come in un risultato inaspettato in qualche fonte esterna al di fuori del programma. Un esempio non riesce a allocare memoria. Un altro non riesce ad aprire un file critico necessario per l'esecuzione del software. Un altro non riesce a connettersi a un server richiesto. Un altro è un utente che blocca un pulsante di interruzione per annullare un'operazione il cui percorso di esecuzione del caso comune prevede di riuscire senza questa interruzione esterna. Tutte queste cose sono al di fuori del controllo del software immediato e dei programmatori che lo hanno scritto. Sono risultati inaspettati da fonti esterne che impediscono all'operazione (che dovrebbe essere considerata una transazione indivisibile nel mio libro *) di riuscire.

Le transazioni

Incoraggio spesso a considerare un tryblocco come una "transazione" perché le transazioni dovrebbero avere successo nel suo insieme o fallire nel suo insieme. Se stiamo provando a fare qualcosa e fallisce a metà strada, allora eventuali effetti collaterali / mutazioni apportati allo stato del programma generalmente devono essere ripristinati per riportare il sistema in uno stato valido come se la transazione non fosse mai stata eseguita affatto, proprio come un RDBMS che non riesce a elaborare una query a metà strada non dovrebbe compromettere l'integrità del database. Se si modifica lo stato del programma direttamente in detta transazione, è necessario "ripristinarlo" al verificarsi di un errore (e qui le protezioni dell'ambito possono essere utili con RAII).

L'alternativa molto più semplice è non mutare lo stato del programma originale; potresti mutare una copia di esso e quindi, se riesce, scambiare la copia con l'originale (assicurandoti che lo scambio non possa essere lanciato). In caso contrario, scartare la copia. Ciò vale anche se non si utilizzano eccezioni per la gestione degli errori in generale. Una mentalità "transazionale" è la chiave per il corretto recupero se si sono verificate mutazioni dello stato del programma prima di riscontrare un errore. O riesce nel suo insieme o fallisce nel suo insieme. A metà strada non riesce a fare le sue mutazioni.

Questo è stranamente uno degli argomenti meno frequentemente discussi quando vedo i programmatori che chiedono come fare correttamente la gestione degli errori o delle eccezioni, ma è il più difficile di tutti ottenere correttamente in qualsiasi software che vuole mutare direttamente lo stato del programma in molti di le sue operazioni. Purezza e immutabilità possono aiutare qui a raggiungere la sicurezza delle eccezioni tanto quanto aiutano con la sicurezza del filo, poiché non è necessario ripristinare un effetto di mutazione / effetto collaterale esterno che non si verifica.

Prestazione

Un altro fattore guida nell'usare o meno le eccezioni è la prestazione, e non intendo in alcun modo ossessivo, schiacciante e controproducente. Molti compilatori C ++ implementano la cosiddetta "gestione delle eccezioni a costo zero".

Offre un overhead di runtime zero per un'esecuzione senza errori, che supera anche quella della gestione degli errori del valore di ritorno C. Come compromesso, la propagazione di un'eccezione ha un grande sovraccarico.

Secondo quanto ho letto al riguardo, i percorsi di esecuzione del tuo caso comune non richiedono alcun sovraccarico (nemmeno l'overhead che normalmente accompagna la gestione e la propagazione del codice di errore in stile C), in cambio di una pesante inclinazione dei costi verso percorsi eccezionali ( il che significa che throwingora è più costoso che mai).

"Caro" è un po 'difficile da quantificare ma, per cominciare, probabilmente non vorrai lanciarti un milione di volte in un circuito ristretto. Questo tipo di progettazione presuppone che non si verifichino eccezioni sempre a destra ea sinistra.

Non Errori

E quel punto prestazionale mi porta a non errori, il che è sorprendentemente sfocato se guardiamo ogni altra lingua. Ma direi, dato il design EH a costo zero di cui sopra, che quasi sicuramente non vuoi throwin risposta a una chiave che non viene trovata in un set. Perché non solo è probabilmente un non errore (la persona che cerca la chiave potrebbe aver creato il set e aspettarsi di cercare chiavi che non sempre esistono), ma sarebbe enormemente costoso in quel contesto.

Ad esempio, una funzione di intersezione di insiemi potrebbe voler scorrere due insiemi e cercare le chiavi che hanno in comune. Se non threwriesci a trovare una chiave , eseguiresti un ciclo continuo e potresti riscontrare eccezioni nella metà o più delle iterazioni:

Set<int> set_intersection(const Set<int>& a, const Set<int>& b)
{
     Set<int> intersection;
     for (int key: a)
     {
          try
          {
              b.find(key);
              intersection.insert(other_key);
          }
          catch (const KeyNotFoundException&)
          {
              // Do nothing.
          }
     }
     return intersection;
}

Quell'esempio sopra è assolutamente ridicolo ed esagerato, ma ho visto, nel codice di produzione, alcune persone che provengono da altre lingue usando le eccezioni in C ++ in qualche modo come questo, e penso che sia un'affermazione ragionevolmente pratica che questo non è un uso appropriato delle eccezioni di sorta in C ++. Un altro suggerimento sopra è che noterai che il catchblocco non ha assolutamente nulla da fare ed è solo scritto per ignorare forzatamente tali eccezioni, e di solito è un suggerimento (anche se non un garante) che le eccezioni probabilmente non vengono utilizzate in modo molto appropriato in C ++.

Per questi tipi di casi, un tipo di valore restituito che indica un errore (qualsiasi cosa, dal ritorno falsea un iteratore non valido nullptro qualsiasi cosa abbia senso nel contesto) è di solito molto più appropriato, e spesso anche più pratico e produttivo poiché un tipo non di errore di case di solito non richiede un processo di svolgimento dello stack per raggiungere il catchsito analogico .

Domande

Dovrei andare con flag di errore interni se scelgo di evitare eccezioni. Sarà troppo fastidioso da gestire o forse funzionerà anche meglio delle eccezioni? Un confronto di entrambi i casi sarebbe la risposta migliore.

Evitare le eccezioni in C ++ mi sembra estremamente controproducente, a meno che tu non stia lavorando in un sistema incorporato o in un particolare tipo di caso che ne proibisce l'uso (nel qual caso dovresti anche fare di tutto per evitare tutto funzionalità di libreria e linguaggio che altrimenti throw, come usare rigorosamente nothrow new).

Se devi assolutamente evitare eccezioni per qualsiasi motivo (es: lavorare attraverso i limiti dell'API C di un modulo di cui esporti l'API C), molti potrebbero non essere d'accordo con me, ma in realtà suggerirei di utilizzare un gestore / stato di errore globale come OpenGL con glGetError(). È possibile utilizzarlo per l'archiviazione locale di thread per avere uno stato di errore univoco per thread.

La mia logica è che non sono abituato a vedere i team negli ambienti di produzione controllare accuratamente tutti i possibili errori, purtroppo quando vengono restituiti i codici di errore. Se fossero approfonditi, alcune API C potrebbero riscontrare un errore in quasi ogni singola chiamata API C e un controllo approfondito richiederebbe qualcosa di simile:

if ((err = ApiCall(...)) != success)
{
     // Handle error
}

... con quasi ogni singola riga di codice che richiama l'API che richiede tali controlli. Eppure non ho avuto la fortuna di lavorare con team così approfonditi. Spesso ignorano tali errori metà, a volte anche la maggior parte delle volte. Questo è il più grande appello per me alle eccezioni. Se avvolgiamo questa API e la rendiamo uniformemente throwal verificarsi di un errore, l'eccezione non può assolutamente essere ignorata e, a mio avviso, ed esperienza, è qui che risiede la superiorità delle eccezioni.

Ma se non è possibile utilizzare le eccezioni, lo stato di errore globale per thread ha almeno il vantaggio (enorme rispetto a me restituire i codici di errore) che potrebbe avere la possibilità di rilevare un errore precedente un po 'più tardi rispetto a quando si è verificato in una base di codice sciatta invece di perdere completamente e lasciarci completamente ignari di ciò che è accaduto. L'errore potrebbe essersi verificato alcune righe prima o in una precedente chiamata di funzione, ma a condizione che il software non si sia ancora arrestato in modo anomalo, potremmo essere in grado di iniziare a lavorare indietro e capire dove e perché si è verificato.

Mi sembra che, dato che i puntatori sono rari, dovrei scegliere dei flag di errore interni se scelgo di evitare le eccezioni.

Non direi necessariamente che i puntatori sono rari. Esistono persino metodi ora in C ++ 11 e versioni successive per ottenere i puntatori di dati sottostanti dei contenitori e una nuova nullptrparola chiave. In genere non è saggio utilizzare i puntatori non elaborati per possedere / gestire la memoria se è possibile utilizzare qualcosa di simile unique_ptrinvece dato quanto sia fondamentale essere conformi alla RAII in presenza di eccezioni. Ma i puntatori grezzi che non possiedono / gestiscono la memoria non sono necessariamente considerati così male (anche da persone come Sutter e Stroustrup) e talvolta molto pratici come un modo per indicare le cose (insieme agli indici che indicano le cose).

Probabilmente non sono meno sicuri degli iteratori di container standard (almeno in versione, iteratori assenti controllati) che non rileveranno se si tenta di dereferenziarli dopo che sono stati invalidati. Il C ++ è ancora senza vergogna un po 'di un linguaggio pericoloso, direi, a meno che il tuo uso specifico di esso non voglia racimolare tutto e nascondere anche puntatori grezzi non proprietari. È quasi fondamentale, con l'eccezione, che le risorse siano conformi a RAII (che generalmente non comporta costi di runtime), ma a parte questo non è necessariamente il linguaggio più sicuro da utilizzare a favore dei costi che uno sviluppatore non desidera esplicitamente scambiare qualcos'altro. L'uso raccomandato non sta cercando di proteggerti da cose come puntatori penzolanti e iteratori invalidati, per così dire (altrimenti saremmo incoraggiati a usareshared_ptrin tutto il luogo, a cui Stroustrup si oppone con veemenza). Sta cercando di proteggerti dal non riuscire a liberare / rilasciare / distruggere / sbloccare / ripulire correttamente una risorsa quando qualcosa throws.


14

Ecco la cosa: a causa della storia unica e della flessibilità di C ++, puoi trovare qualcuno che proclama praticamente qualsiasi opinione su qualsiasi funzionalità che desideri. Tuttavia, in generale, più ciò che stai facendo sembra C, peggio è un'idea.

Uno dei motivi per cui C ++ è molto più flessibile quando si tratta di eccezioni è che non puoi esattamente return nilquando ne hai voglia. Non esiste una cosa come nilnella stragrande maggioranza dei casi e dei tipi.

Ma ecco il semplice fatto. Le eccezioni fanno il loro lavoro automaticamente. Quando si genera un'eccezione, RAII prende il sopravvento e tutto viene gestito dal compilatore. Quando si utilizzano i codici di errore, è necessario ricordarsi di controllarli. Ciò rende intrinsecamente le eccezioni significativamente più sicure dei codici di errore: si controllano, per così dire. Inoltre, sono più espressivi. Lancia un'eccezione e puoi ottenere una stringa che ti dice qual è l'errore e puoi anche contenere informazioni specifiche, come "Parametro X errato che aveva valore Y anziché Z". Ottieni un codice di errore di 0xDEADBEEF e cosa, esattamente, è andato storto? Spero che la documentazione sia completa e aggiornata e anche se ottieni "Parametro errato", non ti dirà mai qualeparametro, quale valore aveva e quale valore avrebbe dovuto avere. Se catturi anche per riferimento, possono essere polimorfici. Infine, si possono generare eccezioni da luoghi in cui i codici di errore non possono mai essere, come i costruttori. E gli algoritmi generici? Come std::for_eachgestirà il tuo codice di errore? Consiglio del professionista: non lo è.

Le eccezioni sono di gran lunga superiori ai codici di errore sotto ogni aspetto. La vera domanda è in eccezioni vs asserzioni.

Ecco la cosa. Nessuno può sapere in anticipo quali sono le condizioni preliminari per il funzionamento del programma, quali condizioni di errore sono insolite, quali possono essere verificate in anticipo e quali sono i bug. Ciò significa generalmente che non è possibile decidere in anticipo se un determinato errore debba essere un'asserzione o un'eccezione senza conoscere la logica del programma. Inoltre, un'operazione che può continuare quando una delle sue sotto-operazioni fallisce è l' eccezione , non la regola.

Secondo me, le eccezioni sono lì per essere colte. Non necessariamente immediatamente, ma alla fine. Un'eccezione è un problema che si prevede che il programma sarà in grado di recuperare da un certo punto. Ma l'operazione in questione non potrà mai riprendersi da un problema che merita un'eccezione.

I fallimenti delle asserzioni sono sempre errori fatali, irrecuperabili. Corruzione della memoria, quel genere di cose.

Quindi, quando non è possibile aprire un file, si tratta di un'asserzione o un'eccezione? Bene, in una libreria generica, ci sono molti scenari in cui l'errore può essere gestito, ad esempio caricando un file di configurazione, potresti semplicemente usare un predefinito predefinito, quindi direi un'eccezione.

Come nota a piè di pagina, vorrei menzionare che c'è qualcosa di "Null Object Pattern" in giro. Questo modello è terribile . Tra dieci anni, sarà il prossimo Singleton. Il numero di casi in cui è possibile produrre un oggetto null adatto è minuscolo .


L'alternativa non è necessariamente un semplice int. Sarebbe più probabile che usassi qualcosa di simile a NSError a cui sono abituato da Obj-C.
Per Johansson,

Paragona non a C, ma all'obiettivo C. È una grande differenza. E i suoi codici di errore spiegano le righe. Al che dici è corretto, non rispondi in qualche modo a questa domanda. Senza offesa.
Gangnus,

Chiunque utilizzi Objective-C, ovviamente, ti dirà che hai assolutamente, completamente torto.
gnasher729,

5

Le eccezioni sono state inventate per un motivo, che è quello di evitare che tutto il codice assomigli a questo:

bool success = function1(&result1, &err);
if (!success) {
    error_handler(err);
    return;
}

success = function2(&result2, &err);
if (!success) {
    error_handler(err);
    return;
}

Invece, ottieni qualcosa che assomiglia di più al seguente, con un gestore di eccezioni in alto maino comunque situato convenientemente:

result1 = function1();
result2 = function2();

Alcune persone dichiarano i vantaggi in termini di prestazioni con l'approccio senza eccezioni, ma a mio avviso la leggibilità riguarda i guadagni di prestazioni minori, soprattutto quando si include il tempo di esecuzione di tutto il if (!success)piatto della caldaia che si deve cospargere ovunque, o il rischio di eseguire il debug di segfault più difficili se non si ' lo includo e considerando le possibilità che si verifichino eccezioni sono relativamente rare.

Non so perché Apple scoraggi l'uso delle eccezioni. Se stanno cercando di evitare la propagazione di eccezioni non gestite, tutto ciò che realizzi realmente è persone che usano puntatori null per indicare invece eccezioni, quindi un errore del programmatore si traduce in un'eccezione puntatore null invece di un file molto più utile che non trova eccezione o altro.


1
Ciò avrebbe più senso se il codice senza eccezioni effettivamente assomigliasse a quello, ma di solito non lo è. Questo modello appare quando error_handler non ritorna mai, ma raramente altrimenti.
Per Johansson,

1

Nel post a cui fai riferimento (eccezioni vs codici di errore), penso che ci sia una discussione leggermente diversa in corso. La domanda sembra essere se hai un elenco globale di codici di errore #define, probabilmente completo di nomi come ERR001_FILE_NOT_WRITEABLE (o abbreviato, se sei sfortunato). E, penso che il punto principale in quel thread sia che se stai programmando in un linguaggio polimorfico, usando istanze di oggetti, un tale costrutto procedurale non è necessario. Le eccezioni possono esprimere quale errore si verifica semplicemente in virtù del loro tipo e possono incapsulare informazioni come il messaggio da stampare (e anche altre cose). Quindi, prenderei quella conversazione come se si debba programmare proceduralmente in un linguaggio orientato agli oggetti o meno.

Ma la conversazione su quando e quanto fare affidamento su eccezioni per la gestione delle situazioni che si presentano nel codice è diversa. Quando vengono generate e rilevate eccezioni, si sta introducendo un paradigma del flusso di controllo completamente diverso dal tradizionale stack di chiamate. Il lancio dell'eccezione è fondamentalmente un'istruzione goto che ti strappa dallo stack delle chiamate e ti invia in una posizione indeterminata (ovunque il codice client decida di gestire l'eccezione). Ciò rende la logica delle eccezioni molto difficile da ragionare .

E così, c'è un sentimento come quello espresso da jheriko che questi dovrebbero essere minimizzati. Cioè, diciamo che stai leggendo un file che potrebbe esistere o meno sul disco. Jheriko e Apple e coloro che la pensano come loro (incluso me stesso) direbbero che non è appropriato lanciare un'eccezione: l'assenza di quel file non è eccezionale , è prevedibile. Le eccezioni non devono sostituire il normale flusso di controllo. È altrettanto facile che il metodo ReadFile () restituisca, ad esempio, un valore booleano e che il codice client visualizzi dal valore restituito false che il file non è stato trovato. Il codice client può quindi dire che il file utente non è stato trovato, o gestire tranquillamente quel caso o qualunque cosa voglia fare.

Quando lanci un'eccezione, stai forzando un onere per i tuoi clienti. Stai dando loro il codice che, a volte, li strapperà dal normale stack di chiamate e li costringerà a scrivere codice aggiuntivo per impedire l'arresto anomalo della loro applicazione. Un onere così potente e sconcertante dovrebbe essere imposto a loro solo se assolutamente necessario in fase di esecuzione, o nell'interesse della filosofia "fail early". Quindi, nel primo caso, puoi generare eccezioni se lo scopo dell'applicazione è monitorare alcune operazioni di rete e qualcuno scollega il cavo di rete (stai segnalando un errore catastrofico). In quest'ultimo caso, potresti generare un'eccezione se il tuo metodo prevede un parametro non nullo e ti viene consegnato null (stai segnalando che sei stato usato in modo inappropriato).

Per quanto riguarda cosa fare invece delle eccezioni nel mondo orientato agli oggetti, ci sono opzioni che vanno oltre il costrutto del codice di errore procedurale. Uno che mi viene subito in mente è che puoi creare oggetti chiamati OperationResult o qualcosa del genere. Un metodo può restituire un OperationResult e quell'oggetto può avere informazioni sulla riuscita o meno dell'operazione e su qualsiasi altra informazione tu voglia che abbia (un messaggio di stato, ad esempio, ma anche, più sottilmente, può incapsulare strategie per il recupero degli errori ). Restituire questo invece di generare un'eccezione consente il polimorfismo, preserva il flusso di controllo e semplifica notevolmente il debug.


Sono d'accordo con te, ma è la ragione per cui la maggior parte sembra non avermi fatto fare questa domanda.
Per Johansson,

0

C'è un bel paio di capitoli in Clean Code che parla proprio di questo argomento - meno il punto di vista di Apple.

L'idea di base è che non restituisci mai zero dalle tue funzioni, perché:

  • Aggiunge molto codice duplicato
  • Crea un pasticcio nel tuo codice - Vale a dire: diventa più difficile da leggere
  • Può spesso causare errori puntatore zero o accedere a violazioni a seconda della particolare "religione" di programmazione

L'altra idea di accompagnamento è che usi le eccezioni perché aiuta a ridurre ulteriormente il disordine nel tuo codice e piuttosto che dover creare una serie di codici di errore che alla fine diventa difficile tenere traccia della gestione e della manutenzione (in particolare su più moduli e piattaforme) e è una seccatura da decifrare per i tuoi clienti, invece crei messaggi significativi che identificano la natura esatta del problema, rendono il debug più semplice e possono ridurre il tuo codice di gestione degli errori a qualcosa di semplice come try..catchun'istruzione di base .

Nei miei giorni di sviluppo COM, avevo un progetto in cui ogni errore sollevava un'eccezione e ogni eccezione aveva bisogno di utilizzare un ID codice di errore univoco basato sull'estensione delle eccezioni COM standard di Windows. Era un blocco di un progetto precedente in cui in precedenza erano stati utilizzati codici di errore, ma la società voleva andare tutti orientati agli oggetti e saltare sul carrozzone COM senza cambiare il modo in cui avevano fatto le cose troppo. Ci sono voluti solo 4 mesi perché esaurissero i numeri di codice di errore e mi sono affidato a refactoring di grandi tratti di codice per utilizzare le eccezioni. Meglio risparmiarti lo sforzo in anticipo e usare solo le eccezioni con giudizio.


Grazie, ma non sto pensando di restituire NULL. Non sembra possibile di fronte ai costruttori. Come ho già detto, probabilmente dovrei usare un flag di errore nell'oggetto.
Per Johansson,
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.