Si dovrebbe derivare / ereditare da std :: exception?

15

Mentre progettavo la mia prima libreria C ++ "seria", mi chiedo:

È un buon stile derivare delle eccezioni da std::exception e sono prole?!

Anche dopo aver letto

Non sono ancora sicuro. Perché, oltre alla pratica comune (ma forse non buona), suppongo, come utente di una libreria, che una funzione di libreria possa generare std::exception s solo quando le funzioni di libreria standard non sono riuscite nell'implementazione della libreria e non può fare nulla esso. Ma ancora, quando scrivo il codice dell'applicazione, per me è molto conveniente, e anche IMHO è buono a lanciare un std::runtime_error . Anche i miei utenti possono contare sull'interfaccia minima definita, come what() o codici.

E ad esempio, il mio utente fornisce argomenti difettosi, cosa sarebbe più conveniente, che lanciare un std::invalid_argument , non è vero? Quindi, combinato con l'uso comune di std :: exception, vedo in altri codice: Perché non andare ancora oltre e derivare dalla tua classe di eccezione personalizzata (ad es. Lib_foo_exception) e anche da std::exception .

Pensieri?

    
posta Superlokkus 22.12.2015 - 14:15
fonte

2 risposte

29

Tutte le eccezioni dovrebbero ereditare da std::exception .

Supponiamo, per esempio, ho bisogno di chiamare ComplexOperationThatCouldFailABunchOfWays() , e voglio gestire tutte le eccezioni che potrebbe generare. Se tutto eredita da std::exception , questo è facile. Ho solo bisogno di un singolo blocco catch e ho un'interfaccia standard ( what() ) per ottenere i dettagli.

try {
    ComplexOperationThatCouldFailABunchOfWays();
} catch (std::exception& e) {
    cerr << e.what() << endl;
}

Se le eccezioni NON ereditano da std::exception , questo diventa molto più brutto:

try {
    ComplexOperationThatCouldFailABunchOfWays();
} catch (std::exception& e) {
    cerr << e.what() << endl;
} catch (Exception& e) {
    cerr << e.Message << endl;
} catch (framework_exception& e) {
    cerr << e.Details() << endl;
}

Riguardo al lancio di runtime_error o invalid_argument rispetto alla creazione di sottoclassi di std::exception da buttare: la mia regola empirica è di introdurre una nuova sottoclasse ogni volta che devo gestire un particolare tipo di errore in modo diverso rispetto ad altri errori ( cioè, ogni volta che ho bisogno di un blocco catch separato).

  • Se introduco una nuova sottoclasse di eccezioni per ogni tipo di errore concepibile, anche se non ho bisogno di gestirli separatamente, allora questo aggiunge un sacco di proliferazione di classe.
  • Se riusino le sottoclassi esistenti per indicare qualcosa di specifico (cioè, se una runtime_error generata qui significa qualcosa di diverso da un errore di runtime generico), allora corro il rischio di entrare in conflitto con altri usi di la sottoclasse esistente.
  • Se I non deve gestire specificamente un errore, e se l'errore che sto lanciando corrisponde esattamente a uno degli errori della libreria standard esistente (come invalid_argument ), allora I riutilizzare la classe esistente. Non vedo molto beneficio nell'aggiungere una nuova classe in questo caso. (Le linee guida C ++ Core non sono d'accordo con me qui - raccomandano sempre di usare le tue classi.)

Le Linee guida del C ++ hanno ulteriori discussioni ed esempi.

    
risposta data 22.12.2015 - 14:44
fonte
9

I would assume, as a library user, that a library function would throw std::exceptions only when standard library functions failed in the library implementation, and it can't do anything about it

Questa è un'ipotesi errata.

I tipi di eccezione standard sono forniti per l'uso "comune". Non sono progettati per solo essere usati dalla libreria standard.

Sì, fai in modo che tutto finisca per ereditare da std::exception . Spesso, ciò comporterà l'ereditare da std::runtime_error o std::logic_error . Qualunque cosa sia appropriata per la classe di eccezione che stai implementando.

Questo è ovviamente soggettivo: diverse librerie popolari ignorano completamente i tipi di eccezioni standard, presumibilmente per separare le librerie dalla libreria standard. Personalmente penso che questo sia estremamente egoistico! Rende le eccezioni di cattura molto più difficili da ottenere.

Parlando di persona, spesso lancio solo un std::runtime_error e ci penso. Ma questo sta entrando in una discussione su come granulare rendere le tue classi di eccezioni, che non è quello che stai chiedendo.

    
risposta data 22.12.2015 - 14:45
fonte

Leggi altre domande sui tag