Подтвердить что ты не робот

Почему 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;
}
4b9b3361

Ответ 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, а все остальные подклассы будут соответствовать второму.