Ich füge diese Antwort hinzu, da es nicht vorteilhaft erscheint, zu diesem Zeitpunkt eine weitere Antwort für diese Frage und Antwort zu erstellen.
In dem Fall, dass Sie Ihre eigene benutzerdefinierte Ausnahme erstellen, die sich von std::exception
Wenn Sie "alle möglichen" Ausnahmetypen abfangen, sollten Sie immer mit der catch
Klauseln mit dem "am meisten abgeleiteten" Ausnahmetyp, der abgefangen werden kann. Siehe das Beispiel (für das, was NICHT zu tun):
#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;
}
HINWEIS:
-
Die richtige Reihenfolge sollte umgekehrt sein, d. h., zuerst müssen Sie catch (const MyException& e)
gefolgt von catch (const std::exception& e)
.
-
Wie Sie sehen können, wird die erste Catch-Klausel ausgeführt, wenn Sie das Programm so ausführen, wie es ist (was Sie wahrscheinlich auch getan haben NICHT in erster Linie wollen).
-
Auch wenn der in der ersten catch-Klausel gefangene Typ vom Typ std::exception
, die "richtige" Version von what()
aufgerufen wird - weil es durch eine Referenz abgefangen wird (ändern Sie zumindest das Argument caught std::exception
und Sie werden das Phänomen des "Object Slicing" in Aktion erleben).
-
Für den Fall, dass der "einige Code aufgrund der Tatsache, dass XXX Ausnahme ausgelöst wurde..." wichtige Dinge MIT BEZUG auf den Ausnahmetyp tut, gibt es Fehlverhalten von Ihrem Code hier.
-
Dies gilt auch, wenn es sich bei den gefangenen Objekten um "normale" Objekte handelt: class Base{};
y class Derived : public Base {}
...
-
g++ 7.3.0
auf Ubuntu 18.04.1 erzeugt eine Warnung, die auf das genannte Problem hinweist:
In der Funktion 'void illustrateDerivedExceptionCatch()': item12Linux.cpp:48:2: Warnung: Ausnahme vom Typ 'MyException' wird gefangen werden catch(const MyException& e) ^~~~~
item12Linux.cpp:43:2: Warnung: durch einen früheren Handler für 'std::exception' catch (const exception& e) ^~~~~
Nochmals Ich möchte darauf hinweisen, dass diese Antwort nur für ADD zu den anderen hier beschriebenen Antworten (ich fand diesen Punkt erwähnenswert, konnte ihn aber nicht in einem Kommentar darstellen).