2013-04-19 10 views
9

Mi sono imbattuto in uno scenario interessante con il controllo del flusso mentre lavoravo sulla mia lingua. Cosa succede se viene generata un'eccezione durante l'elaborazione di un'istruzione break. GCC sembra credere che il flusso di rottura è perso, ma lo standard sembra un po 'in silenzio su ciò che dovrebbe accadere.L'interruzione/proseguimento/ritorno dovrebbe essere interrotta da un'eccezione?

Ad esempio, cosa dovrebbe fare effettivamente il seguente programma?

#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; 
} 

noti che un return verrà bloccata anche, così come un continue (aggiungere uscita dopo la cattura di vedere che). Tentativo di goto anche al di fuori del blocco.

Qual è il flusso corretto? Lo standard non sembra rispondere a questo: la sezione 6.6 sulle dichiarazioni di salto non fa menzione, né la sezione 15 sulla gestione delle eccezioni. Capisco che le eccezioni nei distruttori sono in una forma terribilmente brutta, ma se si utilizza qualcosa come BOOST_SCOPE_EXIT per le dichiarazioni di rinvio, questo comportamento potrebbe diventare piuttosto importante.

Forse di interesse, lo stesso flusso si verifica in Java e Python, quindi almeno sembra esserci una certa coerenza nei linguaggi imperativi.

+0

La tua domanda sembra confermare il consiglio nelle FAQ C++: http://www.parashift.com/c++-faq-lite/dtors-shouldnt-throw.html In pratica, non lanciare eccezioni nei distruttori. Questa domanda nelle FAQ stava dicendo come viene chiamato 'terminate()' se ci si trova in una situazione di "gestione delle eccezioni doppie", ma il tuo esempio sembra continuare il consiglio che è solo brutto farlo. –

+1

@Kevin, assolutamente, quel consiglio si estenderebbe quindi a qualsiasi istruzione "differita" come in qualsiasi lingua (incluso BOOST_SCOPE_EXIT per C++). –

+0

in quale altro modo interpreteresti il ​​comportamento? lanciare l'eccezione nel distruttore e poi cosa? – bdwain

risposta

4

Questo è coperto in 15.1 un'eccezione:

2 Quando viene generata un'eccezione, il controllo viene trasferito al gestore più vicino con un tipo di corrispondenza (15,3); "Più vicino" indica il gestore per il quale l'istruzione composta o l'inizializzatore di identificativi successivi alla parola chiave di prova è stata inserita più di recente dal thread di controllo e non è ancora stata chiusa.

Una volta che il controllo viene trasferito al gestore di eccezioni, continua da lì. Non esiste alcun meccanismo per "ricordare" che il codice si trovava nel mezzo di uno break e quindi riprendere in qualche modo che dopo che l'eccezione è stata gestita.

+0

Non sono sicuro che sia abbastanza chiaro. Si consideri che la sezione 6.6 richiede che le istruzioni di salto facciano come indicato e non menziona l'interruzione di tale flusso. Cioè, penso che il requisito che dichiari e le regole di salto siano in conflitto. –

+0

@ edA-qamort-ora-y Un riferimento allo standard all'effetto di "i distruttori sono chiamati * prima * il salto è avvenuto" rispondere a questa domanda? –

+0

@ edA-qamort-ora-y: Per essere onesti, dopo aver esaminato 6,6 (in particolare il secondo paragrafo), non sono sicuro di vedere l'ambiguità. – NPE

0

Alla luce della specifica dicitura nello stadnard, ho intenzione di dire che è ambiguo. Il testo non è sufficiente per identificare i flussi previsti in queste situazioni. È abbastanza probabile che la convenzione che abbiamo ora sia meramente incidentale a causa della modalità di scrittura dei compilatori.

Consultare l'argomento del mio blog How to catch a "return" statement.

Problemi correlati