Lo tengo semplice.
Una libreria ha un tipo di eccezione di base esteso da std ::: runtime_error (cioè da C ++ si applica come appropriato ad altre lingue). Questa eccezione richiede una stringa di messaggio in modo che possiamo accedere; ogni punto di lancio ha un messaggio univoco (di solito con un ID univoco).
Questo è tutto.
Nota 1 : nelle situazioni in cui qualcuno che rileva l'eccezione può correggere le eccezioni e riavviare l'azione. Aggiungerò eccezioni derivate per cose che possono essere riparate potenzialmente in modo univoco in una posizione remota. Ma questo è molto raro (ricorda che è improbabile che il catcher sia vicino al punto di lancio, quindi risolvere il problema sarà difficile (ma tutto dipende dalla situazione)).
Nota 2 : A volte la libreria è così semplice che non vale la pena dargli una propria eccezione e lo farà std :: runtime_error. È importante avere un'eccezione solo se la capacità di distinguerlo da std :: runtime_error può fornire all'utente informazioni sufficienti per fare qualcosa con esso.
Nota 3 : all'interno di una classe di solito preferisco i codici di errore (ma questi non sfuggiranno mai attraverso l'API pubblica della mia classe).
Guarda i tuoi compromessi:
I trade-off che vedo includono:
More exception classes can allow very fine grain levels of error handling for API users (prone to user configuration or data errors, or files not being found)
Altre eccezioni ti danno davvero un controllo più preciso? La domanda diventa: il codice catching può davvero correggere l'errore in base all'eccezione. Sono sicuro che ci sono situazioni del genere e in questi casi dovresti avere un'altra eccezione. Ma tutte le eccezioni che hai elencato sopra l'unica correzione utile è generare un grosso avvertimento e fermare l'applicazione.
More exception classes allows error specific information to be embedded in the exception, rather than just a string message or error code
Questa è un'ottima ragione per usare le eccezioni. Ma l'informazione deve essere utile alla persona che sta memorizzando la cache. Possono usare le informazioni per eseguire alcune azioni correttive? Se l'oggetto è interno alla tua libreria e non può essere utilizzato per influenzare alcuna API, l'informazione è inutile. Devi essere molto specifico sul fatto che l'informazione generata ha un valore utile per la persona che può prenderlo. La persona che la cattura è solitamente al di fuori dell'API pubblica, quindi personalizza le tue informazioni in modo che possano essere utilizzate con le cose nella tua API pubblica.
Se tutto ciò che possono fare è registrare l'eccezione, allora è meglio lanciare un messaggio di errore piuttosto che molti dati. Poiché il catcher di solito genera un messaggio di errore con i dati. Se crei il messaggio di errore, sarà coerente su tutti i catcher, se permetti al catcher di generare il messaggio di errore potresti ottenere lo stesso errore riportato in modo diverso a seconda di chi sta chiamando e catturando.
Less exceptions, but embedding an error code that can be used as a lookup
Devi determinare il tempo in cui il codice di errore può essere usato in modo significativo. Se può, allora dovresti avere una sua eccezione. Altrimenti ora gli utenti devono implementare le istruzioni switch all'interno di catch (che sconfigge l'intero punto in cui il catch gestisce automaticamente le cose).
Se non è possibile, perché non utilizzare un messaggio di errore nell'eccezione (non è necessario dividere il codice e il messaggio, è un problema cercare).
Returning error codes and flags directly from functions (sometimes not possible from threads)
Il ritorno dei codici di errore è ottimo internamente. Ti permette di correggere i bug lì e poi e devi assicurarti di correggere tutti i codici di errore e di tenerne conto. Ma farli trapelare attraverso la tua API pubblica è una cattiva idea. Il problema è che i programmatori dimenticano spesso di controllare gli stati di errore (almeno con un'eccezione un errore non controllato costringerà l'applicazione a uscire da un errore non gestito in genere corromperà tutti i dati).
Implemented an event or callback system upon error (avoids stack unwinding)
Questo metodo è spesso usato insieme ad altri meccanismi di gestione degli errori (non come alternativa). Pensa al tuo programma Windows. Un utente avvia un'azione selezionando una voce di menu. Questo genera un'azione sulla coda degli eventi. Alla fine la coda di eventi assegna un thread per gestire l'azione. Il thread dovrebbe gestire l'azione e alla fine tornare al pool di thread e attendere un'altra attività. Qui un'eccezione deve essere catturata alla base dal thread assegnato al lavoro. Il risultato dell'ottenere l'eccezione di solito genererà un evento generato per il ciclo principale che alla fine si tradurrà in un messaggio di errore visualizzato all'utente.
Ma a meno che tu non possa continuare a far eccezione all'eccezione, lo stack si srotolerà (almeno per il thread).