Differenza: std :: runtime_error vs std :: exception ()


128

Qual è la differenza tra std::runtime_errore std::exception? Qual è l'uso appropriato per ciascuno? Perché sono diversi in primo luogo?

Risposte:


153

std::exceptionè la classe il cui unico scopo è quello di fungere da classe base nella gerarchia delle eccezioni. Non ha altri usi. In altre parole, concettualmente è una classe astratta (anche se non è definita come classe astratta nel significato C ++ del termine).

std::runtime_errorè una classe più specializzata, discendente da std::exception, destinata a essere lanciata in caso di vari errori di runtime . Ha un duplice scopo. Si può essere gettato da solo, oppure può servire come una classe base a vari tipi ancora più specializzati di eccezioni di errore di runtime, ad esempio std::range_error, std::overflow_errorecc È possibile definire le proprie classi di eccezioni che scende da std::runtime_error, così come è possibile definire la propria eccezione classi discendenti da std::exception.

Proprio come std::runtime_error, contiene la libreria standard std::logic_error, anche discendente std::exception.

Il punto di avere questa gerarchia è dare all'utente la possibilità di utilizzare tutta la potenza del meccanismo di gestione delle eccezioni C ++. Poiché la clausola "catch" può intercettare le eccezioni polimorfiche, l'utente può scrivere clausole "catch" in grado di catturare i tipi di eccezione da una sottostruttura specifica della gerarchia di eccezioni. Ad esempio, catch (std::runtime_error& e)catturerà tutte le eccezioni dalla std::runtime_errorsottostruttura, consentendo a tutti gli altri di passare (e volare più in alto nello stack di chiamate).

PS Progettare una gerarchia di classi di eccezioni utile (che ti consenta di catturare solo i tipi di eccezione che ti interessano in ogni punto del tuo codice) è un'attività non banale. Quello che vedi nella libreria C ++ standard è un possibile approccio, offerto dagli autori del linguaggio. Come vedi, hanno deciso di dividere tutti i tipi di eccezione in "errori di runtime" e "errori logici" e da lì puoi procedere con i tuoi tipi di eccezione. Esistono, ovviamente, modi alternativi per strutturare quella gerarchia, che potrebbe essere più appropriato nel tuo progetto.

Aggiornamento: portabilità Linux vs Windows

Come hanno notato Loki Astari e unixman83 nella loro risposta e nei commenti che seguono, il costruttore della exceptionclasse non accetta alcun argomento secondo lo standard C ++. Microsoft C ++ ha un costruttore che accetta argomenti nella exceptionclasse, ma questo non è standard. La runtime_errorclasse ha un costruttore che prende argomenti ( char*) su entrambe le piattaforme, Windows e Linux. Per essere portatile, un uso migliore runtime_error.

(E ricorda, solo perché una specifica del tuo progetto dice che il tuo codice non deve essere eseguito su Linux, non significa che non debba mai essere eseguito su Linux.)


1
grazie. Bella risposta. anche se mi chiedo se c'è mai la necessità di avere un diverso tipo di eccezione ... solo un pensiero però.
sivabudh,

1
Se esiste una potabilità da cui l'eccezione può essere coperta nuovamente, un diverso tipo di eccezione può essere utile in quanto possiamo utilizzare il meccanismo di gestione delle eccezioni per indirizzare l'eccezione al gestore che tenterà di correggere il problema. Se non esiste alcuna possibilità di recupero, va bene una delle eccezioni standard.
Martin York,

1
A parte questo: non esiste una regola, da nessuna parte, che ti costringa a derivare std::exception. Certo, tutto stdgetta delle classi derivate di ciò, ma non c'è assolutamente alcun motivo per lanciare solo std::exceptionoggetti derivati.
rubenvb,

1
@rubenvb Non lo sapevo, ma penso che chiarirà il codice per la futura manutenzione se vengono lanciati solo oggetti di classi derivati ​​dall'eccezione. Esempio: mi piace scoprire quali eccezioni personalizzate sono implementate nella mia base di codice e cercare le classi derivate dall'eccezione.
stesso

21

std::exceptiondovrebbe essere considerata (nota la considerata) la base astratta della gerarchia di eccezioni standard. Questo perché non esiste alcun meccanismo per passare un messaggio specifico (per fare ciò è necessario derivare e specializzarsi what()). Non c'è nulla che ti impedisca di usare std :: exception e per le applicazioni semplici potrebbe essere tutto ciò di cui hai bisogno.

std::runtime_errord'altra parte ha costruttori validi che accettano una stringa come messaggio. Quando what()viene chiamato viene restituito un puntatore const char che punta a una stringa C che ha la stessa stringa passata nel costruttore.

try
{
    if (badThingHappened)
    {
         throw std::runtime_error("Something Bad happened here");
    }
}
catch(std::exception const& e)
{
    std::cout << "Exception: " << e.what() << "\n";
} 

1
Grazie per la risposta Martin. Tuttavia, utilizzo std :: exception () nello stesso modo in cui hai descritto sopra. cioè il costruttore std :: exception () può anche prendere un carattere std :: string () o const *.
sivabudh,

14
Non secondo lo standard. std :: exception ha un costruttore che non accetta argomenti. L'uso di una versione che accetta uno std :: string o una C-String non è portatile.
Martin York,

10
A causa di Microsoft, mi sono abituato a lanciare std::exception(std::string). Ora mi rendo conto che devo lanciare std::runtime_errorse voglio che il mio codice funzioni in Linux (GCC).
unixman83,
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.