Come posso catturare tutti i tipi di eccezioni in un blocco catch?
-
09-06-2019 - |
Domanda
In C++, sto cercando di catturare tutti i tipi di eccezioni in un'unica cattura (come catch(Exception)
in C#).Com'è fatto?E soprattutto, come si possono individuare le eccezioni di divisione per zero?
Soluzione
catch (...)
{
// Handle exceptions not covered.
}
Considerazioni importanti:
- Un approccio migliore consiste nel rilevare tipi specifici di eccezioni da cui è possibile effettivamente recuperare anziché tutte le possibili eccezioni.
- catch(...) rileverà anche alcune eccezioni gravi a livello di sistema (varia a seconda del compilatore) da cui non sarai in grado di recuperare in modo affidabile.Catturarli in questo modo, poi ingoiarli e continuare potrebbe causare ulteriori seri problemi al tuo programma.
- A seconda del contesto può essere accettabile utilizzare catch(...), a condizione che l'eccezione venga nuovamente lanciata.In questo caso, si registrano tutte le informazioni utili sullo stato locale e quindi si lancia nuovamente l'eccezione per consentirne la propagazione.Comunque dovresti documentarti su Modello RAII se scegli questo percorso
Altri suggerimenti
Voi non voglio usare catch (...) (i.e.catturare con i puntini di sospensione) a meno che tu non ne abbia davvero, sicuramente, e in modo dimostrabile, bisogno.
La ragione di ciò è che alcuni compilatori (Visual C++ 6 per citare i più comuni) trasformano anche errori come errori di segmentazione e altre condizioni davvero pessime in eccezioni che puoi gestire volentieri utilizzando catch (...).Questo è molto brutto, perché non vedi più gli arresti anomali.
E tecnicamente, sì, puoi anche catturare la divisione per zero (dovrai "StackOverflow" per questo), ma in primo luogo dovresti evitare di fare tali divisioni.
Invece, procedi come segue:
- Se sai effettivamente che tipo di eccezioni aspettarti, cattura quei tipi e non altro, e
- Se hai bisogno di lanciare eccezioni tu stesso e devi catturare tutte le eccezioni che lancerai, fai in modo che queste eccezioni derivino da std::exception (come suggerito da Adam Pierce) e catturalo.
Se utilizzi Windows e devi gestire errori come la divisione per zero e la violazione di accesso, puoi utilizzare un traduttore di eccezioni strutturato.E poi all'interno del tuo traduttore puoi lanciare un'eccezione C++:
void myTranslator(unsigned code, EXCEPTION_POINTERS*)
{
throw std::exception(<appropriate string here>);
}
_set_se_translator(myTranslator);
Nota, il codice ti dirà qual era l'errore.Inoltre è necessario compilare con l'opzione /EHa (C/C++ -> Code Generatrion -> Abilita eccezioni C/C++ = Sì con eccezioni SEH).
Se ciò non ha senso controlla i documenti per [_set_se_translator](http://msdn.microsoft.com/en-us/library/5z4bw5h5(VS.80).aspx)
Se catturare tutte le eccezioni, comprese quelle del sistema operativo, è davvero ciò di cui hai bisogno, devi dare un'occhiata al tuo compilatore e al tuo sistema operativo.Ad esempio, su Windows probabilmente hai la parola chiave "__try" o l'opzione del compilatore per fare in modo che "try/catch" catturi le eccezioni SEH o entrambi.
Fai in modo che tutte le tue classi di eccezioni personalizzate ereditino da std::exception, quindi puoi semplicemente catturare std::exception.Ecco qualche esempio di codice:
class WidgetError
: public std::exception
{
public:
WidgetError()
{ }
virtual ~WidgetError() throw()
{ }
virtual const char *what() const throw()
{
return "You got you a widget error!";
}
};
In C++, lo standard non definisce un'eccezione di divisione per zero e le implementazioni tendono a non lanciarla.
Puoi, ovviamente, usare catch (...) { /* code here */ }
, ma dipende davvero da cosa vuoi fare.In C++ hai distruttori deterministici (nessuna di quelle sciocchezze di finalizzazione), quindi se vuoi ripulire, la cosa corretta da fare è usare RAII.
Per esempio.invece di:
void myfunc()
{
void* h = get_handle_that_must_be_released();
try { random_func(h); }
catch (...) { release_object(h); throw; }
release_object(h);
}
Fai qualcosa del tipo:
#include<boost/shared_ptr.hpp>
void my_func()
{
boost::shared_ptr<void> h(get_handle_that_must_be_released(), release_object);
random_func(h.get());
}
Crea la tua classe con un distruttore se non usi boost.
Se ricordo bene (è passato un po' di tempo dall'ultima volta che ho guardato il C++), penso che quanto segue dovrebbe fare al caso mio
try
{
// some code
}
catch(...)
{
// catch anything
}
e una rapida ricerca su Google(http://www.oreillynet.com/pub/a/network/2003/05/05/cpluspocketref.html) sembra darmi ragione.