Voluto ADD alle altre risposte qui descritte una nota aggiuntiva, in caso di eccezioni personalizzate .
Nel caso in cui si crei la propria eccezione personalizzata, da cui deriva std::exception
, quando si rilevano i tipi di eccezioni "tutti i possibili", è necessario avviare sempre le catch
clausole con il tipo di eccezione "più derivato" che può essere rilevato. Vedi l'esempio (di cosa NON fare):
#include <iostream>
#include <string>
using namespace std;
class MyException : public exception
{
public:
MyException(const string& msg) : m_msg(msg)
{
cout << "MyException::MyException - set m_msg to:" << m_msg << endl;
}
~MyException()
{
cout << "MyException::~MyException" << endl;
}
virtual const char* what() const throw ()
{
cout << "MyException - what" << endl;
return m_msg.c_str();
}
const string m_msg;
};
void throwDerivedException()
{
cout << "throwDerivedException - thrown a derived exception" << endl;
string execptionMessage("MyException thrown");
throw (MyException(execptionMessage));
}
void illustrateDerivedExceptionCatch()
{
cout << "illustrateDerivedExceptionsCatch - start" << endl;
try
{
throwDerivedException();
}
catch (const exception& e)
{
cout << "illustrateDerivedExceptionsCatch - caught an std::exception, e.what:" << e.what() << endl;
// some additional code due to the fact that std::exception was thrown...
}
catch(const MyException& e)
{
cout << "illustrateDerivedExceptionsCatch - caught an MyException, e.what::" << e.what() << endl;
// some additional code due to the fact that MyException was thrown...
}
cout << "illustrateDerivedExceptionsCatch - end" << endl;
}
int main(int argc, char** argv)
{
cout << "main - start" << endl;
illustrateDerivedExceptionCatch();
cout << "main - end" << endl;
return 0;
}
NOTA:
0) L'ordine corretto dovrebbe essere viceversa, cioè prima tu catch (const MyException& e)
che è seguito da catch (const std::exception& e)
.
1) Come puoi vedere, quando esegui il programma così com'è, verrà eseguita la prima clausola catch (che è probabilmente quello che NON volevi in primo luogo).
2) Anche se il tipo catturato nella prima clausola catch è di tipo std::exception
, what()
verrà chiamata la versione "corretta" di - perché viene catturata per riferimento (cambia almeno il std::exception
tipo di argomento catturato in base al valore - e sperimenterai il fenomeni di "slicing object" in azione).
3) Nel caso in cui "un po 'di codice a causa del fatto che l'eccezione XXX è stata generata ..." fa cose importanti PER QUANTO RIGUARDA il tipo di eccezione, qui c'è un comportamento scorretto del tuo codice.
4) Ciò è rilevante anche se gli oggetti catturati erano oggetti "normali" come: class Base{};
e class Derived : public Base {}
...
5) g++ 7.3.0
su Ubuntu 18.04.1 produce un avviso che indica il problema menzionato:
Nella funzione 'void illustrateDerivedExceptionCatch ()': item12Linux.cpp: 48: 2: avviso: verrà catturata l' eccezione del tipo 'MyException' (const MyException & e) ^ ~~~~
item12Linux.cpp: 43: 2: avviso: dal gestore precedente per il
catch 'std :: exception' (const exception & e) ^ ~~~~
Di nuovo , dirò, che questa risposta è solo da AGGIUNGERE alle altre risposte qui descritte (ho pensato che questo punto meriti di essere menzionato, ma non sono riuscito a descriverlo in un commento).