Будет ли C++ генерировать без аргументов работать внутри другого фрейма, чтобы перебросить исключение?

Если у меня есть код, подобный следующему:

try {
  doSomething();
} catch (...) {
  noteError();
}

void noteError() {
  try {
    throw;
  } catch (std::exception &err) {
    std::cerr << "Note known error here: " << err.what();
  } catch (...) {
    std::cerr << "Note unknown error here.";
  }
  throw;
}

Будут ли исходные исключения генерироваться из обоих мест внутри нижнего фрейма noteError()?

2 ответа

Решение

Формулировка в стандарте (§15.1/2) (акцент мой):

Когда генерируется исключение, управление передается ближайшему обработчику с соответствующим типом (15.3); "Ближайший" означает обработчик, для которого составной оператор, ctor-initializer или body-body после ключевого слова try был недавно введен потоком управления и еще не завершен.

Когда блок try "вышел"? В соответствии с грамматикой (§15/1) блоки try заканчиваются последовательностью обработчиков, поэтому блок заканчивается, когда заканчивается последний обработчик. Другими словами:

try // <- start of try block
{
}
catch (whatever) // <- first handler
{
}
// ... more handlers
catch (whatever_again) // <- last handler
{
} // <- end of try block

Так что да, ваш код в порядке. При повторной выдаче ближайший блок try имеет соответствующий обработчик (а именно catch (...)), так что обработчик введен.

Ваш оригинальный код был в порядке. Вы перехватили разные типы исключений и вызвали функцию, которая будет регистрировать сообщения и повторно отправлять их. throw Выписка не обязана появляться прямо внутри соответствующего catch блок. Если вы вызываете одну из этих функций "заметки" и в настоящее время вы не обрабатываете исключение, то ваша программа будет вызывать terminate(),

Ваш новый код тоже в порядке. Можно все перехватить, а затем вызвать другую функцию, которая перебрасывается, чтобы перейти к более конкретному обработчику. Это идиома диспетчера исключений, описанная в C++ FAQ. Выглядит немного странно, чтобы сбросить исключение после завершения диспетчерского блока, но если это то же самое throw заявление произошло после noteError вернулся (внутри оригинала catch блок) вместо того, где он сейчас, тогда он будет совершенно обычным; это продемонстрировано в стандарте, §15.1/6.

Другие вопросы по тегам