En C ++, puede especificar que una función puede o no generar una excepción mediante el uso de un especificador de excepción. Por ejemplo:
void foo() throw(); // guaranteed not to throw an exception
void bar() throw(int); // may throw an exception of type int
void baz() throw(...); // may throw an exception of some unspecified type
Dudo de usarlos realmente por lo siguiente:
- El compilador realmente no aplica los especificadores de excepción de manera rigurosa, por lo que los beneficios no son excelentes. Idealmente, le gustaría obtener un error de compilación.
- Si una función viola un especificador de excepción, creo que el comportamiento estándar es terminar el programa.
- En VS.Net, trata el lanzamiento (X) como un lanzamiento (...), por lo que el cumplimiento del estándar no es fuerte.
¿Crees que deberían usarse los especificadores de excepción?
Responda "sí" o "no" y proporcione algunas razones para justificar su respuesta.
Respuestas:
No.
Aquí hay varios ejemplos de por qué:
El código de plantilla es imposible de escribir con especificaciones de excepción,
Las copias pueden arrojarse, el paso de parámetros puede arrojarse y
x()
arrojar alguna excepción desconocida.Las especificaciones de excepción tienden a prohibir la extensibilidad.
podría evolucionar en
Realmente podrías escribir eso como
El primero no es extensible, el segundo es demasiado ambicioso y el tercero es realmente lo que quieres decir cuando escribes funciones virtuales.
Código heredado
Cuando escribe código que se basa en otra biblioteca, realmente no sabe lo que podría hacer cuando algo sale terriblemente mal.
g
terminará, cuandolib_f()
lance. Esto (en la mayoría de los casos) no es lo que realmente quieres.std::terminate()
nunca debe ser llamado Siempre es mejor dejar que la aplicación se bloquee con una excepción no controlada, de la que puede recuperar un seguimiento de la pila, que morir en silencio / violentamente.Escriba código que devuelva errores comunes y tiros en ocasiones excepcionales.
Sin embargo, cuando su biblioteca solo arroja sus propias excepciones, puede usar especificaciones de excepción para indicar su intención.
fuente
try {...} catch (<specified exceptions>) { <do whatever> } catch (...) { unexpected(); ]
construcción, ya sea que quieras o no un bloque de prueba allí.try { <<...code...>> } catch(...) /* stack guaranteed to be unwound here and dtors run */ { throw; /* pass it on to the runtime */ }
terminate()
? ¿Por qué no solo llamasabort()
?Evite las especificaciones de excepción en C ++. Las razones que da en su pregunta son un buen comienzo de por qué.
Vea "Una mirada pragmática a las especificaciones de excepción" de Herb Sutter .
fuente
throw(optional-type-id-list)
) está en desuso en C ++ 11. Todavía están en el estándar, pero supongo que se ha enviado un disparo de advertencia de que su uso debe considerarse con cuidado. C ++ 11 agrega lanoexcept
especificación y el operador. No conozco suficientes detalles sobrenoexcept
para comentarlo. Este artículo parece ser bastante detallado: akrzemi1.wordpress.com/2011/06/10/using-noexcept y Dietmar Kühl tiene un artículo en el Overload Journal de junio de 2011: accu.org/var/uploads/journals/overload103.pdfthrow(something)
se considera inútil y una mala idea.throw()
es útil.Creo que los especificadores de excepción estándar (excepto para C ++)
fueron un experimento en el estándar C ++ que falló en su mayoría.
La excepción es que el especificador no throw es útil, pero también debe agregar internamente el bloque try catch apropiado para asegurarse de que el código coincida con el especificador. Herb Sutter tiene una página sobre el tema. Gotch 82
Además, creo que vale la pena describir las garantías de excepción.
Básicamente, se trata de documentación sobre cómo el estado de un objeto se ve afectado por las excepciones que escapan de un método en ese objeto. Lamentablemente, el compilador no los aplica ni los menciona.
Impulso y excepciones
Garantías de excepción
Sin garantía:
Garantía básica:
Garantía fuerte: (también conocida como Garantía transaccional)
Garantía sin lanzamiento:
fuente
Guarantee that functions will only throw listed exceptions (possibly none)
. No es verdad. Solo garantiza que si la función arroja estas excepciones, la aplicación finalizará.Enable compiler optimizations based on the knowledge that only listed exceptions (possibly none) will be thrown
No puedo hacer eso Porque acabo de señalar que no puede garantizar que no se lanzará la excepción.throw()
(no arroja). " Solo garantiza que si la función arroja estas excepciones, la aplicación terminará " No "no es verdadero" significa verdadero. No hay garantía en C ++ de que una función no llameterminate()
nunca. " Porque acabo de señalar que no puede garantizar que no se lanzará la excepción " Usted garantiza que la función no se lanzará. Que es exactamente lo que necesitas.gcc emitirá advertencias cuando viole las especificaciones de excepción. Lo que hago es usar macros para usar las especificaciones de excepción solo en un modo "pelusa" compilar expresamente para verificar que las excepciones estén de acuerdo con mi documentación.
fuente
El único especificador de excepción útil es "throw ()", como en "no arroja".
fuente
Las especificaciones de excepción no son herramientas maravillosamente útiles en C ++. Sin embargo, hay / es / un buen uso para ellos, si se combina con std :: inesperado.
Lo que hago en algunos proyectos es código con especificaciones de excepción, y luego llamar a set_unexpected () con una función que arrojará una excepción especial de mi propio diseño. Esta excepción, después de la construcción, obtiene una traza inversa (de manera específica de la plataforma) y se deriva de std :: bad_exception (para permitir que se propague si se desea). Si causa una llamada terminate (), como suele suceder, el rastreo se imprime con what () (así como la excepción original que lo causó; no es difícil encontrarlo) y así obtengo información de dónde estaba mi contrato violado, como qué excepción inesperada de la biblioteca se produjo.
Si hago esto, nunca permitiré la propagación de excepciones de la biblioteca (excepto las estándar) y derivar todas mis excepciones de std :: exception. Si una biblioteca decide lanzar, atraparé y convertiré en mi propia jerarquía, lo que me permitirá controlar siempre el código. Las funciones con plantilla que llaman a funciones dependientes deben evitar especificaciones de excepción por razones obvias; pero es raro tener una interfaz de función con plantilla con código de biblioteca de todos modos (y pocas bibliotecas realmente usan plantillas de manera útil).
fuente
Si está escribiendo un código que será utilizado por personas que preferirían mirar la declaración de la función que cualquier comentario al respecto, entonces una especificación les dirá qué excepciones pueden querer atrapar.
De lo contrario, no me parece particularmente útil usar nada más
throw()
que indicar que no arroja ninguna excepción.fuente
No. Si los usa y se produce una excepción que no especificó, ya sea por su código o por el código invocado por su código, entonces el comportamiento predeterminado es terminar rápidamente su programa.
Además, creo que su uso ha quedado en desuso en los borradores actuales del estándar C ++ 0x.
fuente
Una especificación "throw ()" permite que el compilador realice algunas optimizaciones al hacer un análisis de flujo de código si sabe que la función nunca arrojará una excepción (o al menos promete nunca lanzar una excepción). Larry Osterman habla de esto brevemente aquí:
http://blogs.msdn.com/larryosterman/archive/2006/03/22/558390.aspx
fuente
Generalmente no usaría especificadores de excepción. Sin embargo, en los casos en los que, si alguna otra excepción viniera de la función en cuestión, el programa definitivamente no podría corregir , entonces puede ser útil. En todos los casos, asegúrese de documentar claramente qué excepciones podrían esperarse de esa función.
Sí, el comportamiento esperado de una excepción no especificada lanzada desde una función con especificadores de excepción es llamar a terminate ().
También señalaré que Scott Meyers aborda este tema en C ++ más eficaz. Su C ++ efectivo y C ++ más efectivo son libros muy recomendados.
fuente
Sí, si te interesa la documentación interna. O tal vez escribir una biblioteca que otros usarán, para que puedan saber lo que sucede sin consultar la documentación. Lanzar o no lanzar puede considerarse parte de la API, casi como el valor de retorno.
Estoy de acuerdo, no son realmente útiles para forzar la corrección del estilo Java en el compilador, pero es mejor que nada o comentarios casuales.
fuente
Pueden ser útiles para las pruebas unitarias, de modo que al escribir pruebas sepa qué esperar que la función arroje cuando falla, pero no hay cumplimiento que las rodee en el compilador. Creo que son códigos adicionales que no son necesarios en C ++. Cualquiera que elija, de lo que debe estar seguro es que sigue el mismo estándar de codificación en todo el proyecto y los miembros del equipo para que su código siga siendo legible.
fuente
Del artículo:
http://www.boost.org/community/exception_safety.html
Y de hecho, puedo pensar en formas de hacer que las clases de plantillas sean seguras. A menos que no tenga control sobre todas las subclases, puede tener un problema de todos modos. Para hacer esto, podría crear typedefs en sus clases que definan las excepciones lanzadas por varias clases de plantillas. Esto piensa que el problema es siempre abordarlo después en lugar de diseñarlo desde el principio, y creo que esta sobrecarga es el verdadero obstáculo.
fuente
Especificaciones de excepción = basura, pregunte a cualquier desarrollador de Java mayor de 30 años
fuente