2010-09-04 7 views

Respuesta

38

Hay un truco que puede ser capaz de utilizar:

catch(...) { 
    handle_exception(); 
} 

void handle_exception() { 
    try { 
     throw; 
    } catch (const std::exception &e) { 
     std::cout << e.what() << "\n"; 
    } catch (const int i) { 
     std::cout << i << "\n"; 
    } catch (const long l) { 
     std::cout << l << "\n"; 
    } catch (const char *p) { 
     std::cout << p << "\n"; 
    } catch (...) { 
     std::cout << "nope, sorry, I really have no clue what that is\n"; 
    } 

y así sucesivamente, para tantos tipos diferentes que se cree que puede ser lanzado. Si realmente no sabes nada sobre lo que podría arrojarse, incluso ese penúltimo está equivocado, porque alguien podría arrojar un char* que no apunte a una cadena terminada en nul.

En general, es una mala idea lanzar cualquier cosa que no sea std::exception o clase derivada. La razón por la cual std::exception existe es permitir que todos arrojen y atrapen objetos con los que puedan hacer algo útil. En un programa de juguete en el que solo quieres salir de allí y ni siquiera puedes molestarte en incluir un encabezado estándar, OK, tal vez arrojar un int o una cadena literal. No creo que formaría parte de una interfaz formal. Todas las excepciones que arrojes son parte de tu interfaz formal, incluso si de alguna manera olvidaste documentarlas.

+2

Hola; Esta es una respuesta genial. He estado buscando algo de tiempo para encontrar evidencia en los documentos de estándares de que este es un comportamiento estándar, pero no he podido encontrar ninguno. ¿Sabes con certeza que esto es un comportamiento estándar? (Es decir, ingresar un nuevo bloque 'try' dentro de' catch (...) {} 'y volver a lanzar una excepción para determinar su tipo.) – NHDaly

+1

Trabajar desde la memoria: busque el texto sobre la vida útil del excepción actual (hasta que salga de la cláusula catch), y el efecto de un 'throw' sin operando (vuelve a lanzar la excepción actual). –

5

Ese bloque podría atrapar un int, o un const char *, o cualquier cosa. ¿Cómo puede el compilador saber cómo describir algo cuando no sabe nada al respecto? Si desea obtener información de una excepción, debe saber el tipo.

+5

" ¿Cómo puede el compilador saber cómo describir algo cuando sabe? nada sobre eso? " - +1, pero en realidad, el compilador sabe un poco al respecto. El mecanismo de excepción debe almacenar * algún tipo de información, porque tiene que coincidir el objeto de excepción con las cláusulas catch. Pero el estándar no define esta información ni proporciona acceso a ella, es un detalle de implementación oculto. –

+0

Esa información de tipo no es suficiente para realizar esta operación, y ninguna implementación podría cambiar eso. – Puppy

+1

suena como un desafío ;-) Una extensión de compilador '__what()' que devuelve una cadena que contiene el nombre typeinfo de la excepción actual (fácil de implementar) seguida de más caracteres que describen su valor (en la práctica podría cubrirse tediosa pero fácilmente) tipos incorporados, y la mayoría de la biblioteca estándar, y tal vez tengan algunas implementaciones básicas para tipos definidos por el usuario). Por supuesto, esto significaría que el compilador emite un código poco completo para cada tipo para hacer su conversión de cadenas, pero luego piense cuántos 'operator <<' ya existen. Hacerlo por todo, por supuesto no es posible. –

4

Si sabe que sólo un tiro std :: excepción o subclases, tratar

catch(std::exception& e) {...e.what()... } 

De lo contrario, como escribió DeadMG, ya que se puede tirar todo (o casi), no se puede asumir nada acerca de lo que pillan.

Normalmente catch (...) debería usarse solo como la última defensa cuando se usan bibliotecas externas mal escritas o documentadas. Así que usaría una jerarquía

catch(my::specialException& e) { 
     // I know what happened and can handle it 
     ... handle special case 
     } 
catch(my::otherSpecialException& e) { 
     // I know what happened and can handle it 
     ... handle other special case 
     } 
catch(std::exception& e) { 
     //I can at least do something with it 
     logger.out(e.what()); 
     } 
catch(...) { 
    // something happened that should not have 
    logger.out("oops"); 
    } 
2

Cómo hemos implementado nuestros excepciones es que, tenemos nuestras propias clases de excepción, que surgen del std::exception ..

Nuestros excepciones contendrán Mensaje de excepción, Función nombre, nombre de archivo y línea donde se generan excepciones. Todo esto es útil no solo para mostrar los mensajes, sino que también se puede usar para registrar , lo que ayuda a diagnosticar la excepción con bastante facilidad. Entonces, obtenemos la información completa sobre las Excepciones generadas.

Recuerde que las excepciones son para us para obtener información sobre lo que salió mal. Por lo tanto, cada bit de información ayuda en este sentido ..

3

Como C++ 11 puede capturar la excepción actual con un puntero:

std::exception_ptr p;  // default initialization is to nullptr 

try { 
     throw 7; 
} 
catch(...) 
{ 
    p = std::current_exception(); 
} 

Esto comporta como un puntero inteligente; siempre que haya al menos un puntero apuntando al objeto de excepción, no se destruye.

tarde (quizás incluso en una función diferente) puede tomar acción de una manera similar a la actual respuesta más común:

try { 
    if (p) 
     std::rethrow_exception(p); 
} 
catch(int x) 
{ 

} 
catch(std::exception &y) 
{ 
} 
2

Citando bobah

#include <iostream> 

#include <exception> 
#include <typeinfo> 
#include <stdexcept> 

int main() 
{ 
    try { 
     throw ...; // throw something 
    } 
    catch(...) 
    { 
     std::exception_ptr p = std::current_exception(); 
     std::clog <<(p ? p.__cxa_exception_type()->name() : "null") << std::endl; 
    } 
    return 1; 
} 
+1

Esto no es estándar ni portátil. Se basa en * detalles específicos de la implementación * que difieren entre los compiladores. 'std :: exception_ptr' es un puntero inteligente compartido a un tipo * no especificado *, por lo que no hay garantía de que exista' __cxa_exception_type() ' –

Cuestiones relacionadas