Хотел ДОБАВИТЬ к другим описанным здесь ответам дополнительную заметку, в случае пользовательских исключений .
В случае, когда вы создаете свое собственное пользовательское исключение, которое происходит 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 (что, вероятно, вы НЕ сделали хотели в первую очередь).
2) Несмотря на то, что тип, перехваченный в первом предложении catch, имеет тип std::exception
, what()
будет вызываться «правильная» версия - потому что она перехватывается по ссылке (измените, по крайней мере, перехваченный std::exception
тип аргумента на значение - и вы увидите явления «нарезки объектов» в действии).
3) В случае, если «некоторый код из-за того, что исключение XXX было сгенерировано ...» делает важные вещи с ответом на тип исключения, здесь происходит неправильное поведение вашего кода.
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 :: exception' (const exception & e) ^ ~~~~
Опять же , я скажу, что этот ответ предназначен только для ДОБАВЛЕНИЯ других описанных здесь ответов (я думал, что этот момент стоит упомянуть, но не смог изобразить его в комментарии).