Espacios de nombres
Variantes
Acciones

Excepciones

De cppreference.com
< cpp‎ | language

El control de excepciones provee una manera de transferir el control e información de algún punto en la ejecución del programa a un controlador asociado con un punto previamente pasado por la ejecución (en otras palabras, el control de excepciones transfiere el control hacia arriba en la pila de llamadas).

Esta traducción favorece el término "control de excepciones" sobre "manejo de excepciones" o "tratado de excepciones" para exception handling, y "controlador de excepciones" para exception handler. Los términos se alinean con las traducciones de controlador de señales (signal handler) y control de errores (error handling). Además, se usan los términos "lanzar" (throw) para señalar el hecho de que las excepciones se lanzan (y no "se arrojan"), y "atrapar" (catch).

Una excepción puede lanzarse mediante una expresión de lanzamiento, dynamic_cast, typeid, expresión new, función de asignación de memoria, y cualquiera de las funciones de la biblioteca estándar que especifican que lanzan excepciones para señalar ciertas condiciones de error (p. ej., std::vector::at, std::string::substr, etc).

Para que una excepción pueda ser atrapada, la expresión de lanzamiento tiene que estar dentro de un bloque try o dentro de una función llamada desde un bloque try, y tiene que haber una cláusula catch que coincida con el tipo del objeto de excepción.

Al declarar una función, se pueden proporcionar las siguientes especificaciones para limitar los tipos de excepciones que una función puede generar:

(hasta C++17)
(desde C++11)

Los errores que surjan durante el control de excepciones son controlados por std::terminate y std::unexpected (hasta C++17).

Contenido

[editar] Uso

Aunque una expresión de lanzamiento puede usarse para transferir el control a un bloque arbitrario de código subiendo por la pila de ejecución, por razones arbitrarias (similares a std::longjmp), su uso previsto es el control de errores.

[editar] Control de errores

Se usa el lanzamiento de excepción para señalar errores desde funciones, donde los "errores" están típicamente limitados solamente a los siguientes:[1][2][3]:

  1. fallos al no satisfacer las poscondiciones, como no producir un objeto de valor de retorno válido.
  2. fallos al no satisfacer las precondiciones de otra función que debe ser llamada.
  3. (para funciones miembro no privadas) fallos al (re)establecer una invariante de clase.

En particular, esto implica que los fallos de los constructores (véase también RAII) y la mayoría de los operadores deberían ser reportadas lanzando excepciones.

Además, las funciones llamadas de contrato amplio usan excepciones para indicar entradas inaceptables, p. ej., std::string::at no tiene precondiciones, pero lanza una excepción para indicar que el índice está fuera del rango.

[editar] Seguridad de excepciones

Después de que una condición de error se reporta por una función, se pueden proporcionar garantías adicionales con respecto al estado del programa. Los siguientes cuatro niveles de garantías de excepciones se reconocen generalmente[4][5][6], que son un superconjuntos estrictos entre sí:

  1. Garantía de excepción de no lanzamiento (nothrow o nofail) – La función nunca lanza excepciones. No se espera ningún lanzamiento (los errores se reportan por otros medios o se ocultan) de los destructores y otras funciones que puedan llamarse durante el desenredo de la pila. Los destructores son noexcept por defecto. (desde C++11) Se espera no lanzamiento (la función siempre tiene éxito) de intercambios (swaps), constructores de movimiento, y otras funciones usadas por aquellas que proporcionan la garantía de excepción fuerte.
  2. Garantía de excepción fuerte – Si la función lanza una excepción, el estado del programa se revierte al estado justo antes de la llamada a función (p. ej., std::vector::push_back).
  3. Garantía de excepción básica – Si la función lanza una excepción, el programa está en un estado válido. No hay perdida de recursos y todas las invariantes de todos los objetos están intactas.
  4. Sin garantía de excepción – Si la función lanza una excepción, el programa puede no estar en un estado válido: pueden haber ocurrido perdidas de recursos, corrupción de memoria, u otros errores que destruyan las invariantes.

Los componentes genéricos pueden, además, ofrecer una garantía de excepción neutral: si se lanza una excepción desde un parámetro de plantilla (p. ej., del objeto función Compare de std::sort o del constructor de T en std::make_shared), se propaga, sin cambio, al llamador.

[editar] Objetos de excepción

Aunque se pueden lanzar objetos de cualquier tipo completo y punteros a void calificados-cv como objetos de excepción, todas las funciones de la biblioteca estándar lanzan objetos temporales anónimos por valor, y los tipos de esos objetos se derivan (directamente o indirectamente) de std::exception. Las excepciones definidas por el usuario habitualmente siguen este patrón.[7][8][9]

Para evitar copia innecesaria del objeto de excepción y la división del objeto, la mejor práctica para cláusulas catch es capturar por referencia.[10][11][12][13]

[editar] Referencias

 
  1. H. Sutter (2004) "When and How to Use Exceptions" in Dr. Dobb's
  2. H.Sutter, A. Alexandrescu (2004), "C++ Coding Standards", Item 70
  3. C++ Core Guidelines I.10: Use exceptions to signal a failure to perform a required task
  4. B. Stroustrup (2000), "The C++ Programming Language"Appendix E"
  5. H. Sutter (2000) "Exceptional C++"
  6. D. Abrahams (2001) "Exception Safety in Generic Components"
  7. D. Abrahams (2001) "Error and Exception Handling"
  8. isocpp.org Super-FAQ "What should I throw?"
  9. C++ Core Guidelines E.14: Use purpose-designed user-defined types as exceptions (not built-in types)
  10. C++ Core Guidelines E.15: Throw by value, catch exceptions from a hierarchy by reference
  11. S. Meyers (1996) "More Effective C++" Item 13
  12. isocpp.org Super-FAQ "What should I catch?"
  13. H.Sutter, A. Alexandrescu (2004) "C++ Coding Standards" Item 73