Je voulais AJOUTER aux autres réponses décrites ici une note supplémentaire, dans le cas des exceptions personnalisées .
Dans le cas où vous créez votre propre exception personnalisée, qui dérive de std::exception
, lorsque vous interceptez "tous les types d'exceptions" possibles, vous devez toujours démarrer les catch
clauses avec le type d'exception "le plus dérivé" qui peut être intercepté. Voir l'exemple (de ce qu'il ne faut PAS faire):
#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;
}
REMARQUE:
0) L'ordre correct doit être vice-versa, c'est-à-dire d'abord vous catch (const MyException& e)
qui est suivi par catch (const std::exception& e)
.
1) Comme vous pouvez le voir, lorsque vous exécutez le programme tel quel, la première clause catch sera exécutée (ce qui est probablement ce que vous ne vouliez PAS en premier lieu).
2) Même si le type capturé dans la première clause catch est de type std::exception
, la version "appropriée" de what()
sera appelée - car elle est capturée par référence (changez au moins le std::exception
type d' argument capturé par valeur - et vous rencontrerez phénomènes de "tranchage d'objets" en action).
3) Dans le cas où "un certain code dû au fait que l'exception XXX a été levée ..." fait des choses importantes EN CE QUI CONCERNE le type d'exception, il y a un mauvais comportement de votre code ici.
4) Ceci est également pertinent si les objets capturés étaient des objets "normaux" comme: class Base{};
et class Derived : public Base {}
...
5) g++ 7.3.0
sur Ubuntu 18.04.1 génère un avertissement qui indique le problème mentionné:
Dans la fonction 'void illustreDerivedExceptionCatch ()': item12Linux.cpp: 48: 2: avertissement: une exception de type 'MyException' sera interceptée catch (const MyException & e) ^ ~~~~
item12Linux.cpp: 43: 2: avertissement: par un gestionnaire antérieur pour la
capture de "std :: exception" (const const & e) ^ ~~~~
Encore une fois , je dirai que cette réponse n'est qu'à AJOUTER aux autres réponses décrites ici (je pensais que ce point valait la peine d'être mentionné, mais je ne pouvais pas le décrire dans un commentaire).