Требуется ДОБАВИТЬ к другим описанным здесь дополнительным примечаниям, в случае пользовательских исключений .
В случае, когда вы создаете свое собственное пользовательское исключение, которое происходит от std::exception
, когда вы перехватываете «все возможные» типы исключений, вы всегда должны начинать предложения catch
с «самым производным» исключениемТип, который может быть пойман.См. Пример (из того, что НЕ сделать):
#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;
}
ПРИМЕЧАНИЕ:
0) Правильный порядок должен быть наоборот, т. е. сначала вы catch (const MyException& e)
, за которым следует catch (const std::exception& e)
.
1) Как вы можете видеть, когда вы запустите программу как есть, будет выполнено первое предложение catch (что, вероятно, то, что выдействительно, NOT требуется в первую очередь).
2) Даже если тип, перехваченный в первом предложении catch, относится к типу std::exception
, «правильная» версия what()
будетбыть вызванным - потому что он перехватывается по ссылке (измените, по крайней мере, тип перехваченного аргумента std::exception
на значение - и вы увидите явление "разрезания объекта" в действии).
3) В случае, если«некоторый код из-за того, что было сгенерировано исключение XXX ...» делает важные вещи WITH RESPECT для типа исключения, здесь присутствует неправильное поведение вашего кода.
4) Это также актуально, если перехваченообъекты были "нормальными" объектами, такими как: class Base{};
и class Derived : public Base {}
...
5) g++ 7.3.0
в Ubuntu 18.04.1 выдает предупреждение, указывающее на упомянутую проблему:
В функции 'void illustrateDerivedExceptionCatch ()': item12Linux.cpp: 48: 2: предупреждение: исключение типа 'MyException ' будет пойман catch (const MyException & e) ^ ~~~~
item12Linux.cpp: 43: 2: предупреждение: от более раннего обработчика для' std:: исключение ' catch (const exception & e) ^ ~~~~
Снова , я скажу, что этот ответ только на ДОБАВЬТЕ к другим ответам, описанным здесь (я думал, что этот момент стоит упомянуть, но не смог изобразить его в комментарии).