c++ - semanas - abortar, terminar o salir?
imagenes de un aborto espontaneo (6)
Mi consejo sería no usar ninguno de ellos. En cambio, capte las excepciones que no puede manejar en main () y simplemente regrese desde allí. Esto significa que tiene garantizado que el desenrollado de la pila se realiza correctamente y se invocan todos los destructores. En otras palabras:
int main() {
try {
// your stuff
}
catch( ... ) {
return 1; // or whatever
}
}
¿Cuál es la diferencia entre esos tres y cómo debo finalizar el programa en caso de excepción que no puedo manejar correctamente?
std :: abort y std :: exit (y más: std :: _ Exit, std :: quick_exit) son solo funciones de nivel inferior. Los usa para decirle al programa exactamente lo que quiere que haga: qué destructores (y si) llamar, qué otras funciones de limpieza llamar, qué valor devolver, etc.
std :: terminate es una abstracción de nivel superior: se llama (ya sea en tiempo de ejecución o usted) para indicar que se produjo un error en el programa y que, por alguna razón, no es posible manejarlo lanzando una excepción. La necesidad de esto normalmente ocurre cuando ocurre un error en el mecanismo de excepción en sí, pero puede usarlo en cualquier momento cuando no desee que su programa continúe más allá del error dado. Recopilé la lista completa de situaciones cuando se llama a std :: terminate en mi publicación . No se especifica qué hace std :: terminate, porque usted tiene el control de él. Puede configurar el comportamiento registrando cualquier función. Las limitaciones que tiene son que la función no puede regresar al sitio de error y no puede salir a través de una excepción, pero técnicamente puede incluso iniciar su bomba de mensajes dentro. Para ver la lista de cosas útiles que puedes hacer dentro, mira mi otra publicación .
En particular, tenga en cuenta que std :: terminate se considera un manejador de excepciones en contextos en los que se llama a std :: terminate debido a una excepción lanzada que no pudo ser manejada, y puede verificar cuál fue la excepción e inspeccionarla utilizando C ++ 11 usando std :: rethrow_exception y std :: current_exception. Todo está en mi publicación .
Si su programa tiene varios subprocesos, entonces la llamada a exit()
probablemente resulte en un bloqueo porque se intentará destruir los objetos std::thread
globales / estáticos sin salir de sus subprocesos.
Si desea devolver un código de error y salir del programa (más o menos) normalmente, llame a quick_exit()
en programas de subprocesos múltiples. Para una terminación anómala (sin posibilidad de especificar el código de error), se puede abort()
o std::terminate()
.
Nota: quick_exit () no ha sido admitido por MSVC ++ hasta la versión 2015.
- terminar te deja la posibilidad de registrar lo que sucederá cuando se llame. Debería ser uno de los otros dos.
- la salida es una salida normal que permite especificar un estado de salida. Los manejadores registrados por at_exit () se ejecutan
- abortar es una salida anormal. Lo único que se ejecuta es el manejador de señal para SIGABRT.
terminate () se llama automáticamente cuando se produce una excepción que no se puede manejar. Por defecto, terminate () llama a abort (). Puede establecer un identificador personalizado con la función set_terminate ().
abort () envía la señal SIGABRT.
exit () no es necesariamente algo malo. Sale con éxito de la aplicación y llama a las funciones atexit () en orden LIFO. Normalmente no veo esto en aplicaciones C ++, sin embargo, sí lo veo en muchas aplicaciones basadas en Unix donde envía un código de salida al final. Por lo general, una salida (0) indica una ejecución exitosa de la aplicación.
abortar indica el final "anormal" del programa, y aumenta la señal POSIX SIGABRT, lo que significa que cualquier controlador que haya registrado para esa señal se invocará, aunque el programa aún terminará palabras posteriores en cualquier caso. Usualmente usaría
abort
en un programa C para salir de un caso de error inesperado donde el error probablemente sea un error en el programa, en lugar de algo como una mala entrada o una falla en la red. Por ejemplo, puedeabort
si se encuentra que una estructura de datos tiene un puntero NULL cuando lógicamente nunca debería suceder.exit indica un final "normal" al programa, aunque esto aún puede indicar una falla (pero no un error). En otras palabras, puede
exit
con un código de error si el usuario dio una entrada que no se pudo analizar, o un archivo no se pudo leer. Un código de salida de 0 indica éxito.exit
también llama opcionalmente a los manejadores antes de que finalice el programa. Estos están registrados con las funcionesatexit
yon_exit
.std :: terminate es lo que se llama automáticamente en un programa C ++ cuando hay una excepción no controlada. Esto es esencialmente el equivalente de C ++ al
abort
, suponiendo que está informando todos sus errores excepcionales mediante el lanzamiento de excepciones. Esto llama a un controlador establecido por la funciónstd::set_terminate
, que de forma predeterminada simplemente llama aabort
.
En C ++, generalmente quiere evitar abort
llamadas o exit
por error, ya que es mejor lanzar una excepción y dejar que el código más arriba en la pila de llamadas decida si el final del programa es apropiado o no. Si utiliza o no la exit
para tener éxito es una cuestión de circunstancias, tenga o no tenga sentido finalizar el programa en algún lugar que no sea la declaración de devolución en main
.
std::terminate
debe considerarse una herramienta de informe de errores de último momento, incluso en C ++. El problema con std::terminate
es que el manejador de terminación no tiene acceso a la excepción que no se manejó, por lo que no hay forma de saber qué era. Por lo general, es mucho mejor que envuelva la totalidad de main en un bloque try { } catch (std::exception& ex) { }
. Al menos, entonces puede reportar más información acerca de las excepciones derivadas de std::exception
(aunque, por supuesto, las excepciones que no se derivan de std::exception
aún no se manejarán).
Envolver el cuerpo de main
en try { } catch(...) { }
no es mucho mejor que establecer un manejador de terminación, porque nuevamente no tienes acceso a la excepción en cuestión. Editar: Según la respuesta de Neil Butterworth, hay un beneficio en que la pila se desenrolla en este caso, lo que (algo sorprendentemente) no es cierto para una excepción no controlada.