Diferencia: std :: runtime_error vs std :: exception ()

128

¿Cuál es la diferencia entre std::runtime_errory std::exception? ¿Cuál es el uso apropiado para cada uno? ¿Por qué son diferentes en primer lugar?

sivabudh
fuente

Respuestas:

153

std::exceptiones la clase cuyo único propósito es servir como la clase base en la jerarquía de excepciones. No tiene otros usos. En otras palabras, conceptualmente es una clase abstracta (aunque no se define como clase abstracta en el significado C ++ del término).

std::runtime_errores una clase más especializada, descendente std::exception, destinada a ser lanzada en caso de varios errores de tiempo de ejecución . Tiene un doble propósito. Se puede lanzar por sí mismo, o puede servir como una clase base para varios tipos aún más especializados de excepciones de errores de tiempo de ejecución, como std::range_error, std::overflow_erroretc. Puede definir sus propias clases de excepción que descienden std::runtime_error, así como también puede definir su propia excepción clases descendientes de std::exception.

Al igual que std::runtime_error, la biblioteca estándar contiene std::logic_error, también descendiendo de std::exception.

El punto de tener esta jerarquía es dar al usuario la oportunidad de usar toda la potencia del mecanismo de manejo de excepciones de C ++. Dado que la cláusula 'catch' puede capturar excepciones polimórficas, el usuario puede escribir cláusulas 'catch' que pueden capturar tipos de excepción de un subárbol específico de la jerarquía de excepciones. Por ejemplo, catch (std::runtime_error& e)capturará todas las excepciones del std::runtime_errorsubárbol, permitiendo que todos los demás pasen (y vuelen más arriba en la pila de llamadas).

PD: Diseñar una jerarquía de clases de excepción útil (que le permita detectar solo los tipos de excepción que le interesan en cada punto de su código) es una tarea no trivial. Lo que ve en la biblioteca estándar de C ++ es un enfoque posible, ofrecido por los autores del lenguaje. Como puede ver, decidieron dividir todos los tipos de excepción en "errores de tiempo de ejecución" y "errores lógicos" y le permitieron continuar desde allí con sus propios tipos de excepción. Por supuesto, hay formas alternativas de estructurar esa jerarquía, que podrían ser más apropiadas en su diseño.

Actualización: Portabilidad Linux vs Windows

Como Loki Astari y unixman83 señalaron en su respuesta y comentarios a continuación, el constructor de la exceptionclase no toma ningún argumento de acuerdo con el estándar C ++. Microsoft C ++ tiene un constructor que toma argumentos en la exceptionclase, pero esto no es estándar. La runtime_errorclase tiene un constructor que toma argumentos ( char*) en ambas plataformas, Windows y Linux. Para ser portátil, mejor uso runtime_error.

(Y recuerde, solo porque una especificación de su proyecto dice que su código no tiene que ejecutarse en Linux, no significa que nunca tenga que ejecutarse en Linux).

Hormiga
fuente
1
gracias. gran respuesta. aunque me pregunto si alguna vez es necesario tener un tipo diferente de excepción ... aunque solo sea un pensamiento.
sivabudh
1
Si hay una potabilidad desde la cual se puede volver a cubrir la excepción, entonces un tipo diferente de excepción puede ser útil, ya que podemos usar el mecanismo de manejo de excepciones para dirigir la excepción al controlador que intentará corregir el problema. Si no hay posibilidad de recuperación, una de las excepciones estándar está bien.
Martin York el
1
Solo como un aparte: no hay una regla, en ningún lugar, que te obligue a derivar std::exception. Claro, todas las stdcosas arrojan clases derivadas de eso, pero no hay absolutamente ninguna razón para lanzar solo std::exceptionobjetos derivados.
rubenvb
1
@rubenvb No sabía sobre eso, pero creo que aclarará el código para el mantenimiento futuro si solo se lanzan objetos de clases derivados de excepciones. Ejemplo: me gusta averiguar qué excepciones personalizadas se implementan en mi base de código y buscar clases derivadas de excepciones.
this.myself
21

std::exceptiondebe considerarse (tenga en cuenta lo considerado) la base abstracta de la jerarquía de excepción estándar. Esto se debe a que no existe un mecanismo para pasar un mensaje específico (para hacerlo, debe derivar y especializarse what()). No hay nada que le impida usar std :: exception y para aplicaciones simples puede ser todo lo que necesita.

std::runtime_errorpor otro lado tiene constructores válidos que aceptan una cadena como mensaje. Cuando what()se llama, se devuelve un puntero const char que apunta a una cadena C que tiene la misma cadena que se pasó al constructor.

try
{
    if (badThingHappened)
    {
         throw std::runtime_error("Something Bad happened here");
    }
}
catch(std::exception const& e)
{
    std::cout << "Exception: " << e.what() << "\n";
} 
Martin York
fuente
1
Gracias por la respuesta Martin. Sin embargo, uso std :: exception () de la misma manera que describiste anteriormente. es decir, el constructor std :: exception () también puede tomar std :: string () o const char *.
sivabudh
14
No de acuerdo con el estándar. std :: exception tiene un constructor que no toma argumentos. Usar una versión que acepte un std :: string o un C-String no es portátil.
Martin York el
10
Debido a Microsoft, me acostumbré a tirar std::exception(std::string). Ahora me doy cuenta de que debo tirar std::runtime_errorsi quiero que mi código funcione en Linux (GCC).
unixman83