Lo mantengo semplice.
Una libreria ha un tipo di eccezione di base esteso da std ::: runtime_error (che viene dal C ++ si applica come appropriato ad altre lingue). Questa eccezione accetta una stringa di messaggio in modo che possiamo accedere; ogni punto di lancio ha un messaggio unico (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 potenzialmente risolte in modo univoco in una posizione remota. Ma questo è molto raro (ricorda che è improbabile che il ricevitore 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 darla con una propria eccezione e std :: runtime_error lo farà. È importante avere un'eccezione solo se la capacità di distinguerla da std :: runtime_error può fornire all'utente informazioni sufficienti per farci qualcosa.
Nota 3 : All'interno di una classe di solito preferisco i codici di errore (ma questi non sfuggiranno mai all'API pubblica della mia classe).
Guardando i tuoi compromessi:
I compromessi che vedo includono:
Altre classi di eccezioni possono consentire livelli molto precisi di gestione degli errori per gli utenti API (inclini alla configurazione dell'utente o errori di dati o file non trovati)
Più eccezioni ti danno davvero un controllo più preciso del grano? 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 è quella di generare un grande avviso e interrompere l'applicazione.
Più classi di eccezioni consentono di incorporare nell'eccezione informazioni specifiche sull'errore, anziché solo un messaggio di stringa o un codice di errore
Questa è un'ottima ragione per usare le eccezioni. Ma le informazioni devono essere utili alla persona che le sta memorizzando nella cache. Possono utilizzare le informazioni per eseguire alcune azioni correttive? Se l'oggetto è interno alla tua libreria e non può essere utilizzato per influenzare nessuna delle API, le informazioni sono inutili. Devi essere molto preciso sul fatto che le informazioni generate hanno un valore utile per la persona che può catturarle. La persona che li cattura di solito si trova all'esterno dell'API pubblica, quindi personalizza le tue informazioni in modo che possano essere utilizzate con le cose nell'API pubblica.
Se tutto ciò che possono fare è registrare l'eccezione, allora è meglio semplicemente lanciare un messaggio di errore piuttosto che molti dati. Poiché il ricevitore genererà di solito un messaggio di errore con i dati. Se si genera il messaggio di errore, questo sarà coerente tra tutti i catcher, se si consente al catcher di creare il messaggio di errore, è possibile ottenere lo stesso errore riportato in modo diverso a seconda di chi sta chiamando e intercettando.
Meno eccezioni, ma incorporando un codice di errore che può essere utilizzato come ricerca
Devi determinare il tempo in cui il codice di errore può essere utilizzato in modo significativo. Se è possibile, dovresti avere la sua eccezione. Altrimenti i tuoi utenti ora devono implementare le istruzioni switch all'interno del catch (che sconfigge l'intero punto di avere il catch gestire automaticamente le cose).
Se non è possibile, perché non utilizzare un messaggio di errore nell'eccezione (non è necessario dividere il codice e il messaggio rende difficile cercare).
Restituzione di codici di errore e flag direttamente dalle funzioni (a volte non è possibile dai thread)
Restituire i codici di errore è ottimo internamente. Ti consente di correggere i bug lì e poi e devi assicurarti di correggere tutti i codici di errore e tenerne conto. Ma farle passare attraverso l'API pubblica è una cattiva idea. Il problema è che i programmatori spesso dimenticano di verificare gli stati di errore (almeno con un'eccezione un errore non controllato costringerà l'applicazione a chiudere un errore non gestito in genere corromperà tutti i tuoi dati).
Implementato un evento o un sistema di callback in caso di errore (evita il riavvolgimento dello stack)
Questo metodo viene spesso utilizzato insieme ad altri meccanismi di gestione degli errori (non in alternativa). Pensa al tuo programma Windows. Un utente avvia un'azione selezionando una voce di menu. Questo genera un'azione sulla coda degli eventi. La coda degli eventi alla fine assegna un thread per gestire l'azione. Il thread dovrebbe gestire l'azione e infine tornare al pool di thread e attendere un'altra attività. Qui un'eccezione deve essere rilevata alla base dal thread assegnato al lavoro. Il risultato della cattura dell'eccezione di solito comporta la generazione di un evento per il ciclo principale che alla fine comporterà la visualizzazione di un messaggio di errore per l'utente.
Ma a meno che tu non possa continuare di fronte all'eccezione, lo stack si svolgerà (almeno per il thread).