2013-04-19 1 views
9

Я столкнулся с интересным сценарием с контролем потока во время работы на моем языке. Что произойдет, если при обработке инструкции break возникает исключение. Кажется, что GCC полагает, что поток прерывается, но стандарт кажется несколько молчащим о том, что должно произойти.Должно ли прерывание/продолжение/возвращение прерываться за счет исключения?

Например, что должна делать следующая программа?

#include <iostream> 
using namespace std; 

struct maybe_fail { 
    bool fail; 
    ~maybe_fail() { 
     if(fail) 
      throw 1; 
    } 
}; 

int main() { 
    for(int i=0; i < 6; ++i) { 
     cout << "Loop: " << i << endl; 

     try { 
      maybe_fail mf; 
      mf.fail = i % 2; 
      if(i == 3) 
       break; 

     } catch(int) { 
      cout << "Caught" << endl; 
     } 
    } 
    return 0; 
} 

Обратите внимание, что return также будет заблокирован, как будет continue (добавить выход после улова, чтобы увидеть, что). Попадание на goto за пределами блока также будет поймано.

Каков правильный поток? Стандарт, похоже, не затрагивает этого: раздел 6.6 о инструкциях перехода не упоминает, также раздел 15 об обработке исключений. Я понимаю, что исключения в деструкторах в ужасно плохом виде, но если вы используете что-то вроде BOOST_SCOPE_EXIT для заявлений о задержке, это поведение может стать весьма важным.

Возможно, интересный, тот же поток происходит в Java и Python, поэтому, по крайней мере, на императивных языках существует определенная последовательность.

+0

Ваш вопрос, кажется, подтверждает совет в FAQ на C++: http://www.parashift.com/c++-faq-lite/dtors-shouldnt-throw.html В принципе, не бросайте исключения в деструкторы. Этот вопрос в FAQ часто указывал, как вызывается 'terminate()', если вы находитесь в ситуации с «двойным исключением», но ваш пример, похоже, продолжает давать советы, что это просто плохо. –

+1

@Kevin, абсолютно, этот совет будет распространяться на любой оператор «defer» на любом языке (включая BOOST_SCOPE_EXIT для C++). –

+0

как еще вы могли бы интерпретировать поведение? выбросить исключение в деструктор, а потом что? – bdwain

ответ

4

Это описано в 15.1 Метательный исключение:

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

После того, как управление передано обработчику исключений, оно просто продолжается оттуда. Нет никакого механизма, чтобы «помнить», что код находился в середине break, а затем каким-то образом возобновил его после обработки исключения.

+0

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

+0

@ edA-qamort-ora-y Будет ли ссылка на стандарт влиять на «деструкторы называются * до того, как произошел скачок» ответ на этот вопрос? –

+0

@ edA-qamort-ora-y: Если честно, посмотрев на 6.6 (особенно второй абзац), и я не уверен, что вижу двусмысленность. – NPE

0

В свете конкретной формулировки в прислуге я собираюсь сказать, что это неоднозначно. Текст недостаточен для определения предполагаемых потоков этих ситуаций. Вполне возможно, что соглашение, которое мы имеем сейчас, является просто случайным из-за того, как написаны компиляторы.

См. Мою статью в блоге How to catch a "return" statement.

 Смежные вопросы

  • Нет связанных вопросов^_^