¿Cuándo y cómo debo usar el manejo de excepciones?

Estoy leyendo sobre el manejo de excepciones. Obtuve cierta información sobre el manejo de excepciones, pero tengo algunas preguntas:

  1. ¿Cuándo lanzar una excepción?
  2. En lugar de lanzar una excepción, ¿podemos usar un valor de retorno para indicar el error?
  3. Si protejo todas mis funciones con bloques try-catch, ¿no reducirá el rendimiento?
  4. ¿Cuándo usar el manejo de excepciones?
  5. Vi un proyecto en el que todas y cada una de las funciones de ese proyecto contenían un bloque try-catch (es decir, el código dentro de toda la función está rodeado por el bloque try-catch). ¿Es esta una buena practica?
  6. ¿Cuál es la diferencia entre try-catch y __try __except?

Aquí hay una guía bastante completa sobre excepciones que creo que es una lectura obligada:

Excepciones y manejo de errores – C ++ FAQ o C ++ FAQ lite

Como regla general, haga una excepción cuando su progtwig pueda identificar un problema externo que impida la ejecución. Si recibe datos del servidor y esos datos no son válidos, genere una excepción. ¿Sin espacio en disco? Lanza una excepción. ¿Los rayos cósmicos le impiden consultar la base de datos? Lanza una excepción. Pero si obtiene datos no válidos desde su propio progtwig, no arroje una excepción. Si su problema proviene de su propio código incorrecto, es mejor utilizar ASSERT para evitarlo. El manejo de excepciones es necesario para identificar problemas que el progtwig no puede manejar y decirles sobre el usuario, porque el usuario puede manejarlos. Pero los errores en su progtwig no son algo que el usuario pueda manejar, por lo que el locking del progtwig no dirá mucho menos que “El valor de answer_to_life_and_universe_and_everything no es 42! Esto nunca debería suceder !!!! 11” excepción.

Capture una excepción donde puede hacer algo útil con ella, como mostrar un cuadro de mensaje. Prefiero atrapar una excepción una vez dentro de una función que de alguna manera maneja la entrada del usuario. Por ejemplo, el usuario presiona el botón “Aniquilar a todos los hunams”, y dentro de la función aniquilarAllHunamsClicked () hay un bash … atrapar el bloque para decir “No puedo”. Aunque la aniquilación de hunamkind es una operación compleja que requiere llamar a docenas y docenas de funciones, solo hay una prueba … catch, porque para un usuario es una operación atómica: haga clic en un botón. Los controles de excepción en cada función son redundantes y desagradables.

Además, no puedo recomendarle que se familiarice con RAII, es decir, asegurarse de que todos los datos que se inicialicen se destruyan automáticamente. Y eso se puede lograr inicializando tanto como sea posible en la stack, y cuando necesite inicializar algo en el montón, use algún tipo de puntero inteligente. Todo lo inicializado en la stack se destruirá automáticamente cuando se lanza una excepción. Si utiliza punteros tontos estilo C, corre el riesgo de pérdida de memoria cuando se lanza una excepción, porque no hay nadie para limpiarlos en la excepción (seguro, puede utilizar punteros tipo C como miembros de su clase, pero asegúrese de que son cuidado en destructor).

Las excepciones son útiles en una variedad de circunstancias.

Primero, hay algunas funciones donde el costo de calcular la condición previa es tan alto que es mejor hacer el cálculo y abortar con una excepción si se encuentra que la condición previa no se cumple. Por ejemplo, no puede invertir una matriz singular; sin embargo, para calcular si es singular, calcule el determinante que es muy costoso: de todos modos debe realizarse dentro de la función, de modo que simplemente “intente” invertir la matriz e informe un error si no puede lanzar una excepción. Esto es básicamente una excepción como uso negativo previo a la condición .

Luego hay otros casos en los que su código ya es complejo y es difícil pasar la información de error a la cadena de llamadas. Esto se debe en parte a que C y C ++ tienen modelos de estructura de datos rotos: hay otras formas mejores, pero C ++ no las admite (como el uso de mónadas en Haskell). Este uso es básicamente que no me molestaría hacerlo bien, así que lanzaré una excepción : no es el camino correcto, pero es práctico.

Luego está el uso principal de las excepciones: informar cuándo las precondiciones externas o invariantes, tales como recursos suficientes como la memoria o el espacio en disco, no están disponibles. En este caso, generalmente terminará el progtwig, o una subsección principal del mismo, y la excepción es una buena forma de transmitir información sobre el problema. Las excepciones de C ++ se diseñaron para informar errores que impiden que el progtwig continúe .

Se sabe que el modelo de manejo de excepciones utilizado en la mayoría de los lenguajes modernos, incluido C ++, se ha roto. Es muy poderoso. Los teóricos ahora han desarrollado mejores modelos que el modelo completamente abierto “arroje todo” y “tal vez y tal vez no lo capte”. Además, el uso de información tipo para clasificar excepciones no era una muy buena idea.

Así que lo mejor que puedes hacer es lanzar excepciones con moderación, cuando hay un error real, y cuando no hay otra manera de lidiar con él y capturar excepciones tan cerca del punto de lanzamiento como sea posible .

Mejor lectura para esto

El manejo de excepciones se ha hablado mucho en la última década y media. Sin embargo, a pesar del consenso general sobre cómo manejar adecuadamente las excepciones, sigue existiendo una división en el uso. El manejo de excepciones incorrecto es fácil de detectar, fácil de evitar y es una métrica de calidad simple de código (y desarrollador). Sé que las reglas absolutas son tan directas o exageradas, pero como regla general, no debes usar try / catch

http://codebetter.com/karlseguin/2010/01/25/don-t-use-try-catch/

Si su problema proviene de su propio código incorrecto, es mejor utilizar ASSERT para evitarlo. El manejo de excepciones es necesario para identificar problemas que el progtwig no puede manejar y decirles sobre el usuario, porque el usuario puede manejarlos. Pero los errores en su progtwig no son algo que el usuario pueda manejar, por lo que el locking del progtwig no dirá mucho

No estoy de acuerdo con este aspecto de la respuesta aceptada . Una afirmación no es mejor que arrojar una excepción. Si las excepciones fueron adecuadas solo para errores de tiempo de ejecución (o “problemas externos”), ¿para qué sirve std::logic_error ?

Un error lógico es casi por definición el tipo de condición que impide que un progtwig continúe. Si el progtwig es una construcción lógica, y una condición ocurre fuera del dominio de esa lógica, ¿cómo puede continuar? ¡Reúne tus entradas mientras puedas y lanza una excepción!

No es que no haya arte previo. std::vector , para nombrar uno, arroja una excepción de error lógico, a saber, std::out_of_range . Si utiliza la biblioteca estándar y no tiene un controlador de nivel superior para detectar las excepciones estándar, solo para llamar a what () y exit (3), entonces sus progtwigs estarán sujetos a una terminación abrupta y silenciosa.

Una macro afirmar es una guardia mucho más débil. No hay recuperación A menos que, es decir, no esté ejecutando una comstackción de depuración, en cuyo caso no hay ejecución . La macro afirmar pertenece a una era en la que el cálculo era 6 órdenes de magnitud más lento que el actual. Si se toma la molestia de probar los errores lógicos, pero no usar esa prueba cuando sea necesario, en producción, ¡será mejor que confíe en su código!

La biblioteca estándar proporciona excepciones de error lógico y las emplea. Están ahí por una razón: porque ocurren errores lógicos y son excepcionales. El hecho de que C tenga aserciones no es razón para confiar en un mecanismo tan primitivo (y, sin dudas, inútil), cuando una excepción maneja el trabajo mucho mejor.

1. Se incluye una excepción en el código cuando existe la posibilidad de obtener una excepción como resultado o en algún punto intermedio del problema.

2. Utilice el bloque try-catch solo con aquellos casos donde se requiera. El uso de cada bloque try-catch se agrega a una verificación de condición adicional que ciertamente reduce la optimización del código.

3. Creo que _try_except es un nombre de variable válido …

La diferencia básica es:

  1. uno hace un manejo de errores para usted.
  2. uno es tuyo.

    • Por ejemplo, si tiene una expresión podría hacer 0 divide error . El uso de try catch 1. lo ayudará cuando ocurra un error. O necesitas una if a==0 then.. en 2.

    • Si no intentas atrapar la excepción, no creo que sea más rápido, simplemente se omite, si ocurre un error , se lanzará a un controlador externo.

Entregarse significa que el problema no va más allá y que en muchos casos tiene una ventaja de velocidad, pero no siempre.

Sugerencia: solo manejarte cuando sea simple y lógicamente.

Muchos puristas de C / C ++ desalientan las excepciones por completo. Las principales críticas son:

  1. Es lento – Por supuesto que no es realmente “lento”. Sin embargo, en comparación con c / c ++ puro, hay bastante sobrecarga.
  2. Introduce errores: si no maneja las excepciones correctamente, puede perder el código de limpieza en la función que arroja la excepción.

En su lugar, verifique el código de valor / error de retorno cada vez que llame a una función.