Хотів ADD в інші відповіді , описані тут , необхідно додаткове примітка, в разі користувальницьких винятків .
У випадку, коли ви створюєте власний спеціальний виняток, який випливає з 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) Як ви бачите, при запуску програми такою, якою вона є, буде виконано перше застереження (що, мабуть, те, чого ви НЕ хотіли в першу чергу).
2) Навіть незважаючи на те, що тип, що потрапив у перше застереження про вилов, має тип 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' буде спійманий (const MyException & e) ^ ~~~~
item12Linux.cpp: 43: 2: попередження: попереднім обробником для вибору "std :: виключення"
(виняток const & e) ^ ~~~~
Знову я скажу, що ця відповідь полягає лише в ДОДАТКІ на інші описані тут відповіді (я вважав, що цей момент варто згадати, але не міг змалювати його в коментарі).