#include <exception>
#include <string>
#include <iostream>
class MyException : public std::exception {
public:
MyException(const std::string & msg)
: std::exception(), m_msg(msg)
{
}
const char * what() const throw()
{
return m_msg.c_str();
}
~MyException() throw()
{
}
private:
std::string m_msg;
};
int main()
{
try
{
throw MyException("MyException");
}
catch(std::exception e) //вот тут происходит т.н. "расщепление"
{
std::cout << e.what();
}
return 0;
}
Этот код выведет "std::exception". Это происходит потому, что в строке с инструкцией catch(std::exception e) происходит преобразование к значению базового типа (т.н. "срезка" или "расщепление"), в котором нет строки-члена m_msg, который хранит сообщение об ошибке. То есть, до блока обработки долетает совсем не то, что было сгенерировано внутри try. И выводится именно то, что выводится в std::exception::what(), а не MyException::what(). Чтобы получать правильный тип исключения, надо получать значение по ссылке. То есть заменить "catch(std::exception e)" на "catch(std::exception & e)". Тогда не происходит преобразования к значению класса базового типа и корректно работает механизм полиморфизма. Как с указателями. И в результате мы получаем именно тот объект-исключение, который был сгенерирован в блоке try.
На самом деле не вижу ни одной причины, чтобы не использовать перехват исключений по ссылке всегда. Перехват по значению может привести к описанным выше проблемам, а перехват по указателю обычно ведет к необходимости удалять объект исключения после его обработки. А это лишнее действие, которое можно и забыть сделать. Поэтому проще всего перехватывать исключения по ссылке и не забивать себе голову лишними действиями. Ну а генерировать исключения надо, в таком случае, всегда по значению.
Комментариев нет:
Отправить комментарий