Estado del código que funciona correctamente cuando se lanzan excepciones
La seguridad de excepciones es el estado en el que el código funciona correctamente cuando se lanzan excepciones. [1] Para ayudar a garantizar la seguridad de excepciones, los desarrolladores de la biblioteca estándar de C++ han ideado un conjunto de niveles de seguridad de excepciones , garantías contractuales del comportamiento de las operaciones de una estructura de datos con respecto a las excepciones. Los implementadores y clientes de la biblioteca pueden usar estas garantías al razonar sobre la corrección del manejo de excepciones . Los niveles de seguridad de excepciones se aplican igualmente a otros lenguajes y mecanismos de manejo de errores. [2]
Historia
Como escribe David Abrahams , "nadie habló nunca de 'seguridad ante errores' antes de que C++ tuviera excepciones". [3] El término apareció como tema de publicaciones en JTC1/SC22/WG21 , el comité de estándares de C++, ya en 1994. [4] La seguridad ante excepciones para la biblioteca estándar de C++ fue formalizada por primera vez para STLport por Abrahams, estableciendo la distinción entre seguridad básica/seguridad fuerte. [5] Esto se extendió a las garantías básicas/fuertes/nothrow modernas en una propuesta posterior. [6]
Fondo
Las excepciones proporcionan una forma de flujo de control no local, en el sentido de que una excepción puede "surgir" desde una función llamada. Esta aparición puede provocar un error de seguridad de excepciones al romper invariantes de una estructura de datos mutables, como se indica a continuación: [7]
- Un paso de una operación en una estructura de datos mutable modifica los datos y rompe un invariante.
- Se lanza una excepción y el control "sube", omitiendo el resto del código de la operación que restauraría la invariante.
- Se captura la excepción y se recupera, o
finally
se ingresa un bloqueo. - La estructura de datos con invariante roto es utilizada por el código que asume el invariante, lo que genera un error.
Se puede decir que un código con un error como el anterior es "inseguro frente a excepciones". [7]
Clasificación
La biblioteca estándar de C++ proporciona varios niveles de seguridad de excepciones (en orden decreciente de seguridad): [8]
- Garantía de no repetición , también conocida como transparencia ante fallos : se garantiza que las operaciones se ejecutarán correctamente y cumplirán todos los requisitos incluso en situaciones excepcionales. Si se produce una excepción, se gestionará internamente y los clientes no la tendrán en cuenta.
- Fuerte seguridad de excepciones , también conocida como semántica de confirmación o reversión : las operaciones pueden fallar, pero se garantiza que las operaciones fallidas no tendrán efectos secundarios, dejando los valores originales intactos. [9]
- Seguridad de excepción básica : la ejecución parcial de operaciones fallidas puede provocar efectos secundarios, pero se conservan todos los invariantes . Todos los datos almacenados contendrán valores válidos que pueden diferir de los valores originales. Las fugas de recursos (incluidas las fugas de memoria ) suelen descartarse mediante un invariante que indica que se tienen en cuenta y se gestionan todos los recursos.
- Seguridad sin excepciones : No se ofrecen garantías.
Por lo general, se requiere al menos una seguridad de excepción básica para escribir código robusto. A veces, puede resultar difícil alcanzar niveles de seguridad más altos y pueden generar una sobrecarga debido a la copia adicional. Un mecanismo clave para la seguridad de excepción es una finally
cláusula o una sintaxis de manejo de excepciones similar , que garantiza que cierto código siempre se ejecute cuando se sale de un bloque, incluso por excepciones. Varios lenguajes tienen construcciones que simplifican esto, en particular utilizando el patrón dispose , denominado using
, with
o try
-with-resources.
Ejemplo
Considere un tipo de vector inteligente, como el de C++ o Java . Cuando se agrega un elemento a un vector , el vector debe agregarse a la lista interna de objetos y actualizar un campo de recuento que indica cuántos objetos hay en él . También puede ser necesario asignar nueva memoria si la capacidad existente no es suficiente.std::vector
ArrayList
x
v
x
v
Alternativas de seguridad excepcionales:
- Garantía de no tirar
- Se implementa garantizando que la asignación de memoria nunca falle o definiendo el
insert
comportamiento de la función en caso de falla de asignación (por ejemplo, haciendo que la función devuelva un resultado booleano que indique si se realizó la inserción). - Fuerte seguridad de excepción
- Se implementa haciendo primero cualquier asignación necesaria y luego intercambiando los buffers si no se encuentran errores (el modismo de copiar e intercambiar). En este caso, la inserción de
x
into v
tiene éxito o v
permanece sin cambios a pesar del error de asignación. - Excepción básica de seguridad
- Se implementa garantizando que el campo de conteo refleje el tamaño final de
v
. Por ejemplo, si se encuentra un error, la insert
función puede desasignar por completo v
y restablecer su campo de conteo a cero. En caso de error, no se pierden recursos, pero v
no se conserva el valor anterior de . - Seguridad sin excepciones
- Un error de inserción podría provocar contenido dañado en
v
, un valor incorrecto en el campo de recuento o una pérdida de recursos .
Referencias
- ^ Crichton, Alex (24 de julio de 2015). "Rust RFC: Stabilize catch_panic". El lenguaje de programación Rust . Consultado el 26 de mayo de 2022.
El código es seguro frente a excepciones si funciona correctamente incluso cuando las funciones a las que llama generan excepciones.
- ^ Lau, Ron (10 de noviembre de 2020). "Seguridad de excepciones en el mundo de JS". Medium .
- ^ Dave Abrahams (2000). Seguridad de excepciones en componentes genéricos. Programación genérica . Apuntes de clase sobre informática . Vol. 1766. Springer . Págs. 69-79. doi :10.1007/3-540-39953-4_6. ISBN. 978-3-540-41090-4. Consultado el 29 de agosto de 2008 .
- ^ Colvin, Gregory (1994). "Exception Safe Exceptions" (PDF) . Documentos del Comité de estándares de C++ . Consultado el 17 de diciembre de 2021 .
- ^ Abrahams, David. "STLport: Manejo de excepciones". www.stlport.org . Consultado el 17 de diciembre de 2021 .
- ^ Abrahams, Dave; Colvin, Greg. "Cómo hacer que la biblioteca estándar de C++ sea segura para excepciones" (PDF) . Documentos del Comité de estándares de C++ . Consultado el 17 de diciembre de 2021 .
- ^ ab Crichton, Alex (24 de julio de 2015). «Rust RFC: Stabilize catch_panic». El lenguaje de programación Rust . Consultado el 26 de mayo de 2022 .
- ^ Bjarne Stroustrup (1997). Apéndice E: Seguridad de excepciones de la biblioteca estándar en "El lenguaje de programación C++" (PDF) (3.ª ed.). Addison-Wesley. ISBN 0-201-88954-4.
- ^ Austern, Matt (30 de mayo de 1997). "Standard Library Exception Policy". Documentos del Comité de estándares de C++ . Consultado el 26 de mayo de 2022 .
Enlaces externos
- Herb Sutter: C++ excepcional: 47 problemas de ingeniería, problemas de programación y soluciones, 2000
- Jon Kalb: Codificación segura ante excepciones en C++, con C++Now! Presentaciones de 2012 sobre seguridad ante excepciones.
- Discusión relacionada en Stackoverflow: C++: ¿(realmente) escribes código seguro frente a excepciones?