Почему std:: exception ломает мое исключение перед std:: bad_alloc?
Проблема. Я использую как std:: exception, так и std:: bad_alloc для исключения исключений. Что-то не так с порядком улова try, который я использую. Я приложил пример кода для справки.
Ожидаемый. Если моя ошибка bad_alloc, то генерируется исключение bad_alloc.
Соблюдается. Моя ошибка bad_alloc, но выбрано исключение.
Пример кода:
#include "stdafx.h"
#include <iostream>
#include <exception>
using namespace std;
void goesWrong()
{
bool error1Detected = true;
bool error2Detected = false;
if (error1Detected)
{
throw bad_alloc();
}
if (error2Detected)
{
throw exception();
}
}
int main()
{
try
{
goesWrong();
}
catch (exception &e)
{
cout << "Catching exception: " << e.what() << endl;
}
catch (bad_alloc &e)
{
cout << "Catching bad_alloc: " << e.what() << endl;
}
return 0;
}
Ответы
Ответ 1
Вы должны поместить свои исключения в обратном порядке, в отношении их отношений наследования. std:: exception - это родительский класс std:: bad_alloc, поэтому он найден ранее в списке catch. Поэтому вам нужно преобразовать свой код:
try {
goesWrong();
}
catch (bad_alloc &e)
{
cout << "Catching bad_alloc: " << e.what() << endl;
}
catch (exception &e)
{
cout << "Catching exception: " << e.what() << endl;
}
Вы не ограничены уловом объектов: вы можете бросать целые числа, символы... что угодно. В этом случае catch(...)
- единственный безопасный способ поймать их всех.
Тем не менее, использование объектов из стандартной библиотеки классов - это рекомендуемый способ сделать это. И в этом случае, поскольку std:: exception является базовым классом для всех (стандартных) исключений, он будет улавливать все возможные исключения.
Вы можете создать свои собственные классы исключений, получая их из std:: exception или из std:: runtime_error, например, мой личный выбор.
Надеюсь, что это поможет.
Ответ 2
В С++ порядок, в котором перечислены обработчики исключений, учитывается при сопоставлении обработчиков с исключениями. Первый обработчик, который может обрабатывать исключение, будет вызываться, даже если в списке есть лучшее совпадение. Это отличается от Java или С#, где будет вызываться только лучшее совпадение (и компилятор заставит вас поместить его в начало списка).
Поскольку исключение передается по ссылке, применяется полиморфизм; это означает, что подкласс может быть передан обработчику, который ожидает его родительский класс. Поскольку std:: bad_alloc является подклассом std:: exception, он будет обрабатываться первым блоком catch.
Чтобы получить поведение, которое вы ожидали, поместите блоки блокировки в обратную сторону:
catch (bad_alloc &e)
{
cout << "Catching bad_alloc: " << e.what() << endl;
}
catch (exception &e)
{
cout << "Catching exception: " << e.what() << endl;
}
Таким образом, std:: bad_alloc будет соответствовать первому обработчику, а std:: exception, а все остальные подклассы будут соответствовать второму.