Chciał DODAJ do innych odpowiedzi opisanych tutaj dodatkowa uwaga, w przypadku niestandardowych wyjątków .
W przypadku tworzenia własnego niestandardowego wyjątku, który wywodzi się z tego std::exception
, kiedy wychwytujesz „wszystkie możliwe” typy wyjątków, zawsze powinieneś zaczynać catch
klauzule od „najbardziej pochodnych” typów wyjątków, które mogą zostać przechwycone. Zobacz przykład (czego NIE robić):
#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;
}
UWAGA:
0) Właściwa kolejność powinna być na odwrót, tj. - najpierw ty, catch (const MyException& e)
a następniecatch (const std::exception& e)
.
1) Jak widać, po uruchomieniu programu w obecnej postaci zostanie wykonana pierwsza klauzula catch (prawdopodobnie tego właśnie NIE oczekiwałeś).
2) Mimo że typ wychwycony w pierwszej klauzuli catch jest typu std::exception
, what()
zostanie wywołana „właściwa” wersja - ponieważ zostanie ona przechwycona przez odwołanie (zmień przynajmniej std::exception
typ przechwyconego argumentu na wartość - i doświadczysz zjawiska „krojenia obiektów” w akcji).
3) W przypadku, gdy „jakiś kod z powodu faktu, że został zgłoszony wyjątek XXX ...” robi ważne rzeczy W ODNIESIENIU do typu wyjątku, oznacza to nieprawidłowe zachowanie się kodu.
4) Ma to również znaczenie, jeśli złapane obiekty były obiektami „normalnymi”, takimi jak: class Base{};
i class Derived : public Base {}
…
5) g++ 7.3.0
w systemie Ubuntu 18.04.1 wyświetla ostrzeżenie wskazujące na wspomniany problem:
W funkcji „void illustrateDerivedExceptionCatch ()”: item12Linux.cpp: 48: 2: ostrzeżenie: wyjątek typu „MyException” zostanie przechwycony (const MyException & e) ^ ~~~~
item12Linux.cpp: 43: 2: ostrzeżenie: przez wcześniejszy moduł obsługi dla
catch 'std :: wyjątek' (const wyjątek i e) ^ ~~~~
Znowu powiem, że ta odpowiedź jest DODAJ tylko do innych opisanych tutaj odpowiedzi (myślałem, że ten punkt warto wspomnieć, ale nie mogę go przedstawić w komentarzu).