2010-03-17 12 views
22

Il seguente è ben definito in C++ o no? Sono obbligato a "convertire" le eccezioni in codici restituiti (l'API in questione è utilizzata da molti utenti C, quindi devo assicurarmi che tutte le eccezioni C++ vengano intercettate prima che il controllo venga restituito al chiamante) &.È lanciando un'eccezione legale in un "tentativo" annidato?

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

Spero che il campione mostri la mia intenzione. La mia ipotesi è che questo è un comportamento indefinito, ma non ne sono sicuro. Si prega di fornire preventivi dallo standard, se applicabile. Approcci alternativi sono apprezzati pure.

Grazie!

+1

Ricordo di aver preso in considerazione questo approccio per ridurre la duplicazione del codice derivante da diversi blocchi try/catch, ma l'ho implementato. Cosa ti fa pensare che potrebbe essere illegale? –

+0

L'ho già utilizzato in passato è un'ottima tecnica – iain

+2

@jdv - Mi sentivo un po 'a disagio nel rilanciare da dentro un blocco try nidificato in una catch-clause (e anche in un frame stack diverso). Sembrava un po 'troppo bello, quindi volevo essere al sicuro. –

risposta

12

Va bene. L'eccezione è attiva fino a quando non viene catturata, dove diventa inattiva. Ma sopravvive fino alla fine dell'ambito del gestore. Dalla standard sottolineatura mia:

§15.1/4: La memoria per la copia temporanea del all'eccezione generata viene allocata in modo specificato, eccetto come indicato in 3.7.4.1. Il temporaneo persiste finché c'è un gestore che viene eseguito per quell'eccezione.

Cioè:

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

    /* ... */ 

} // <-- 

Tra quelle frecce, è possibile ri-generare l'eccezione. Solo quando termina l'ambito dei gestori l'eccezione cessa di esistere.

Tenere presente se si chiama dispatch senza un'eccezione attiva, verrà chiamato terminate. Se dispatch genera un'eccezione in uno se sono gestori, l'eccezione inizierà a propagarsi. Maggiori informazioni in a related question.

+0

Va bene usare questo approuch all'interno di un metodo chiamato in un costruttore? (G ++) – agodinhost

2

Dal dispatcher chiamato nel blocco di cattura throw si ripeterà l'eccezione. Se si chiama dispatcher al di fuori blocco allora verrà chiamato terminate() (secondo 15.1/8). Non c'è in ogni caso un comportamento indefinito.

Problemi correlati