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

Является ли повторное бросание исключения законным во вложенной "попытке"?

Является ли следующее определение корректным в С++ или нет? Я вынужден "конвертировать" исключения в коды возврата (рассматриваемый API используется многими пользователями C, поэтому мне нужно убедиться, что все исключения С++ пойманы и обработаны до того, как элемент управления возвращается вызывающему).

enum ErrorCode {…};
ErrorCode dispatcher() {
   try {
      throw;
   }
   catch (std::bad_alloc&) {
      return ErrorCode_OutOfMemory;
   }
   catch (std::logic_error&) {
      return ErrorCode_LogicError;
   }
   catch (myownstdexcderivedclass&) {
      return ErrorCode_42;
   }
   catch(...) {
      return ErrorCode_UnknownWeWillAllDie;
   }
}

ErrorCode apifunc() {
   try {
      // foo() might throw anything
      foo();
   }
   catch(...) {
      // dispatcher rethrows the exception and does fine-grained handling
      return dispatcher();
   }
   return ErrorCode_Fine;
}

ErrorCode apifunc2() {
   try {
      // bar() might throw anything
      bar();
   }
   catch(...) {
      return dispatcher();
   }
   return ErrorCode_Fine;
}

Надеюсь, что образец показывает мое намерение. Я предполагаю, что это поведение undefined, но я не уверен. При необходимости укажите котировки из стандарта. Также оцениваются альтернативные подходы.

Спасибо!

4b9b3361

Ответ 1

Это хорошо. Исключение активно до тех пор, пока оно не поймается, когда оно станет неактивным. Но он живет до тех пор, пока не закончится область действия обработчика. Из стандарта основное внимание уделяется:

§15.1/4: Память для временной копии генерируемого исключения распределяется неопределенным способом, за исключением случаев, указанных в 3.7.4.1. Временное сохранение сохраняется до тех пор, пока выполняется обработчик для этого исключения.

То есть:

catch(...)
{ // <--

    /* ... */

} // <--

Между этими стрелками вы можете повторно выбросить исключение. Только тогда, когда заканчивается область обработчиков, исключение перестает существовать.

Имейте в виду, если вы вызываете dispatch без активного исключения, будет вызван terminate. Если dispatch выдает исключение в одном, если оно обработчиков, это исключение начнет распространяться. Дополнительная информация в связанном вопросе.

Ответ 2

Так как dispatcher, вызываемый в блоке catch throw, будет отменять исключение. Если вы выберете dispatcher вне блока catch, тогда будет вызываться terminate() (согласно 15.1/8). В любом случае поведение undefined отсутствует.