Законно ли повторное генерирование исключения во вложенной «попытке»?

Является ли следующее четко определенным в С++ или нет? Я вынужден «преобразовывать» исключения в возвращаемые коды (рассматриваемый API используется многими пользователями C, поэтому мне нужно убедиться, что все исключения 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, но я не уверен. Пожалуйста, предоставьте цитаты из стандарта, если применимо. Альтернативные подходы также приветствуются.

Спасибо!


person Alexander Gessler    schedule 17.03.2010    source источник
comment
Я помню, как рассматривал этот подход, чтобы уменьшить дублирование кода, возникающее из-за разных блоков try/catch, но я реализовал его. С чего вы взяли, что это может быть незаконно?   -  person    schedule 18.03.2010
comment
Я тоже использовал это раньше, это отличная техника   -  person iain    schedule 18.03.2010
comment
@jdv - мне было немного неудобно перебрасывать из блока try, вложенного в предложение catch (и даже в другой фрейм стека). Это выглядело слишком красиво, поэтому я хотел быть в безопасности.   -  person Alexander Gessler    schedule 18.03.2010
comment
throw без аргументов устарел в С++ 11. Я использовал этот подход в С++ 3 без проблем, однако я получаю одну грязную проблему в g++, пытаясь перенести его (используя rethrow_exception и get_exception).   -  person agodinhost    schedule 08.09.2015
comment
@agodinhost Вау Вау Вау. Вы можете указать этот источник? en.cppreference.com/w/cpp/language/throw Я думаю, вы возможно путаница со спецификациями исключений en.cppreference.com/w/cpp/language/except_spec< /а> !?   -  person sehe    schedule 15.11.2015
comment
Да, ты прав. Ty.   -  person agodinhost    schedule 03.02.2016


Ответы (2)


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

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

Это:

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

    /* ... */

} // <--

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

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

person GManNickG    schedule 17.03.2010
comment
Можно ли использовать этот подход внутри метода, вызываемого в конструкторе? (г++) - person agodinhost; 08.09.2015

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

person Kirill V. Lyadvinsky    schedule 17.03.2010