Come posso migliorare il controllo e la gestione degli errori?


13

Ultimamente ho avuto difficoltà a capire quale sia la giusta quantità di controllo e quali siano i metodi corretti.

Ho alcune domande al riguardo:

Qual è il modo corretto di verificare la presenza di errori (input errato, stati errati, ecc.)? È meglio verificare esplicitamente la presenza di errori o utilizzare funzioni come assert che possono essere ottimizzate dal codice finale? Ho la sensazione di controllare esplicitamente un programma con un sacco di codice extra che non dovrebbe essere eseguito nella maggior parte delle situazioni, e per non parlare della maggior parte degli errori che finiscono con un fallimento di interruzione / uscita. Perché ingombrare una funzione con controlli espliciti solo per interrompere? Ho cercato affermazioni contro il controllo esplicito degli errori e ho trovato poco per spiegare veramente quando fare entrambe le cose.

La maggior parte dice "usa assert per verificare la presenza di errori logici e usa controlli espliciti per verificare altri errori". Questo non sembra portarci molto lontano però. Diremmo che questo è fattibile:

Malloc returning null, check explictly
API user inserting odd input for functions, use asserts

Questo mi renderebbe migliore nel controllo degli errori? Cos'altro posso fare? Voglio davvero migliorare e scrivere codice "professionale" migliore.


3
Bella domanda, ma penso che potrebbe essere più adatto per uno dei siti gemelli (programmatori?).

Grazie, non ne ero sicuro. Ho pensato che da quando il SO era abbastanza legato al codice sarebbe andato tutto bene.
Anon,

3
La semplice risposta è "Ecco perché sono state inventate le eccezioni. Ottieni una lingua migliore".
DeadMG

1
@DeadMG: setjmp/ longjmpsono disponibili in C, quindi non hai bisogno di una nuova lingua.
user786653,

3
@DeadMG: Qualcuno che non riesce a controllare correttamente l'errore C ha una probabilità alle palle di neve all'inferno di gestire correttamente l'eccezione C ++ ...
Coder

Risposte:


4

Il modo più semplice per dire la differenza è determinare se la condizione di errore viene introdotta in fase di compilazione o di esecuzione. Se il problema è in qualche modo un programmatore che utilizza la funzione errata, attendi che attiri l'attenzione sul problema, ma una volta che la correzione è stata compilata nel codice chiamante, non dovrai più preoccuparti di controllarlo. Problemi come esaurire la memoria o input dell'utente finale non valido non possono essere risolti al momento della compilazione, quindi si lasciano i controlli.


2

Controlla qualsiasi cosa in qualsiasi momento (potrebbe essere cambiato dopo l'ultimo controllo) che non è al 100% sotto il tuo comando. E anche: durante lo sviluppo anche non fidarti di te stesso! ;-)

Okokok ... "qualsiasi cosa" deve essere letta come controllo di tali cose che potrebbero causare un'interruzione anomala o qualsiasi cosa che potrebbe far sì che l'applicazione / il sistema facciano cose che non dovrebbero fare.

Per essere seri, l'ultima parte dell'ultima frase è essenziale perché indica il problema principale:

Se vuoi costruire un sistema stabile, la preoccupazione principale non riguarda ciò che il sistema dovrebbe fare, ma per renderlo in grado di fare tali cose obbligatorie, devi prenderti cura di ciò che non dovrebbe fare, anche se "ingombra il tuo codice".


1
+1 per "controlla tutto". Non compro l'argomento del disordine del codice: qualsiasi programmatore dovrebbe essere in grado di distinguere comunque tra controllo degli errori e logica effettiva.
stijn

2

Il nocciolo della gestione degli errori non è se e come affronti il ​​problema. È più di quello che fai dopo averlo appreso .

Prima di tutto, direi che non vi è alcun motivo per cui qualsiasi singolo errore restituito dal metodo subordinato restituito non debba essere gestito. E gli errori e le eccezioni sono poco più che i valori di ritorno o tutti i tentativi / catture.

  1. Basta lanciare e prendere non è sufficiente.
    Vedi questo : dove l'autore spiega che solo catturando ma non facendo nulla elimina potenzialmente l'eccezione e, a meno che non si faccia abbastanza per annullare il danno, è peggio che lasciare che il codice vada proprio così. Allo stesso modo, semplicemente scrivere un'istruzione "log" quando c'è un file aperto o un errore di lettura potrebbe aiutare a trovare il motivo - ma al termine del programma, potrebbe aver causato danni ai dati! Non basta dire che ho molti tentativi / catture - è più importante sapere cosa fanno veramente!

  2. Non abusare del tentativo di cattura.
    Alcune volte - i programmatori per lo più pigri o ingenui pensano che dopo aver scritto sufficienti try / catch, il loro lavoro è finito e facile. Abbastanza spesso è meglio applicare azioni correttive e riprendere piuttosto che scaricare tutto. Se ciò non può essere fatto, è necessario decidere a quale livello è necessario tornare indietro. A seconda del contesto e della gravità, provare a intercettare i bisogni richiede un'attenta progettazione. Ad esempio: vedi questo e questo

  3. Definisci chi è il responsabile:
    Una delle prime cose che dovresti fare è definire se l'input dato alla routine stessa è solo uno scenario inaccettabile (o non gestito finora) o è l'eccezione dovuta all'ambiente (come problema di sistema, problema di memoria) o questa situazione è completamente interna al risultato dell'algoritmo. In tutti i casi, il livello al quale potresti voler tornare o l'azione che desideri intraprendere differisce in modo significativo. In questa luce, vorrei dire che quando si esegue il codice in produzione, fare abort () per uscire dal programma è buono, ma non per ogni piccola cosa. Se noti la corruzione della memoria o esaurisci la memoria, è certo che anche dopo aver fatto del tuo meglio, le cose moriranno. Ma se ricevi un puntatore NULL all'ingresso, non vorrei

  4. Definire qual è il miglior risultato possibile:
    tutto ciò che deve essere fatto in via eccezionale è molto critico. Ad esempio, se in uno dei nostri casi - un lettore multimediale rileva che non ha dati completi che devono essere riprodotti all'utente - che cosa dovrebbe fare?

    • saltare una parte cattiva e vedere se può andare avanti con cose buone.
    • se questo accade troppo, considera se può saltare al brano successivo.
    • se rileva che non è in grado di leggere alcun file, fermati e mostra qualcosa.
    • nel frattempo
    • sotto quale dello stato dovrebbe un giocatore pop-up per l'utente e
    • quando dovrebbe portare da solo?
    • Dovrebbe "arrestare" le cose per chiedere il feedback degli utenti
    • o dovrebbe mettere una piccola nota discreta di errore in qualche angolo?

    Tutti questi sono soggettivi - e forse ci sono più modi per gestire i problemi di noi banalmente cosa. Tutto quanto sopra richiede di costruire e comprendere la profondità dell'eccezione e di realizzare scenari diversi in cui evolvere.

  5. A volte dobbiamo verificare le eccezioni prima che si verifichino. L'esempio più comune è la divisione per zero errori. Idealmente, è necessario verificarlo prima che si verifichi tale eccezione - e in tal caso - provare a mettere il valore non zero più appropriato e andare avanti piuttosto che suicidarsi!

  6. Pulire. Almeno questo è quello che devi fare! Se una funzione capita di aprire 3 file e la quarta non riesce ad aprirsi, inutile dire che i primi 3 avrebbero dovuto essere chiusi. Delegare questo lavoro a un livello sopra è una cattiva idea. se decidi di non andartene senza pulire la memoria. E, cosa più importante, anche se sei sopravvissuto all'eccezione, informa più in alto che le cose non hanno preso il corso normale.

Il modo in cui vediamo la funzionalità (normale) del software in termini di varie gerarchie o livelli o astrazioni, allo stesso modo dobbiamo categorizzare le eccezioni in base alla loro gravità e all'ambito in cui sorgono e stanno influenzando altre parti del sistema - che definisce come gestire eccezioni così diverse nel miglior modo possibile.

Migliore riferimento: Code Craft capitolo 6 - disponibile per il download


1

Il controllo degli errori solo durante le build di debug è BAD IDEA (tm), la compilazione sotto sovrapposizione di rilascio sovrappone variabili riutilizzabili in pila, rimuove le pagine di guardia, fa trucchi incerti con i calcoli, sostituisce gli artritici pesanti con turni precalcolati e così via.

Utilizza anche il controllo degli errori nella versione, puoi ricorrere a qualcosa di semplice come:

if(somethinghitthefan)
     abort();

Questo ha anche un ottimo effetto collaterale che sicuramente non ignorerai il bug una volta che l'applicazione inizia a bloccarsi sul PC di betta tester.

I visualizzatori e i registri degli eventi sono completamente inutili rispetto a abort()chi li controlla comunque?


exit / abort == peggior esperienza utente di sempre: l'applicazione scompare senza dire perché ..
stijn

@stijn: abortinterrompe il debugger / crea un dump. exitè male, sì. Anche se preferisco di __asm int 3più.
Coder

questo è vero, e in C / C ++ tendo a scrivere affermazioni usando anche __asm ​​int 3, ma mai senza mostrare almeno una descrizione del perché, e preferibilmente anche linea e file. Quindi almeno il cliente può fornire informazioni su cosa è successo esattamente.
stijn,

0

Le varie cose che puoi fare sono
1. Leggere e assimilare molto codice online e vedere come è fatto
2. Utilizzare alcuni strumenti di debug in modo da aiutarti a localizzare le regioni di errori
3. Essere consapevoli di errori insignificanti dovuti a assegnazioni improprie e errori di sintassi.
4. Alcuni errori peggiori si verificano a causa di errori logici nel programma che sono più difficili da trovare. Per questo puoi scriverlo e trovarlo o per quelli più complicati prova a parlare con le persone o usa risorse come StackOverflow , Wikipedia , Google per ottenere aiuto da persone.

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.