2010-03-17 9 views
22

¿Está lo siguiente bien definido en C++ o no? Me veo forzado a 'convertir' excepciones en códigos de retorno (la API en cuestión es utilizada por muchos usuarios de C, así que necesito asegurarme de que todas las excepciones de C++ sean interceptadas & antes de que se devuelva el control al llamador).¿Está volviendo a lanzar una excepción legal en un intento anidado?

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

Espero que la muestra muestre mi intención. Creo que esto es un comportamiento indefinido, pero no estoy seguro. Proporcione citas de la norma, si corresponde. También se aprecian enfoques alternativos.

Gracias!

+1

Recuerdo que consideré este enfoque para reducir la duplicación de código que surge de diferentes bloques try/catch, pero lo implementé. ¿Qué te hace pensar que podría ser ilegal? –

+0

Lo he usado antes también es una gran técnica – iain

+2

@jdv - Me sentí un poco incómodo con el replanteo desde dentro de un bloque try anidado en una cláusula catch (e incluso en un marco de pila diferente). Simplemente se veía demasiado hermoso, así que quería estar seguro. –

Respuesta

12

Eso está bien. La excepción está activa hasta que se atrapa, donde se vuelve inactiva. Pero vive hasta que finaliza el alcance del controlador. de la norma, el énfasis es mío:

§15.1/4: La memoria para la copia temporal de la excepción de ser lanzado se asigna de una manera no especificada, excepto como se indica en 3.7.4.1. El temporal persiste siempre que se ejecute un controlador para esa excepción.

Eso es:

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

    /* ... */ 

} // <-- 

Entre esas flechas, se puede volver a emitir la excepción. Solo cuando finaliza el ámbito de los manejadores, la excepción deja de existir.

Tenga en cuenta si llama al dispatch sin una excepción activa, se llamará terminate. Si dispatch arroja una excepción en uno si se trata de manipuladores, esa excepción comenzará a propagarse. Más información en a related question.

+0

¿Estaría bien usar esta aplicación dentro de un método llamado en un constructor? (g ++) – agodinhost

2

Desde dispatcher llamado en el bloque de captura throw se volverá a lanzar la excepción. Si llama al dispatcher fuera del bloque catch, se llamará a terminate() (según 15.1/8). No hay un comportamiento indefinido en ningún caso.

Cuestiones relacionadas