try tipos tipo son que propagacion personalizada manejo lenguaje las instrucciones excepciones excepcion catch c++ exception error-handling language-implementation

tipos - ¿Cómo se implementa el tiempo de ejecución de control de excepciones de C++?



tipos de excepciones en java (4)

Estoy intrigado por cómo funciona el mecanismo de manejo de excepciones de C ++. Específicamente, ¿dónde está almacenado el objeto de excepción y cómo se propaga a través de varios ámbitos hasta que se detecta? ¿Está almacenado en algún área global?

Dado que esto podría ser específico del compilador, ¿alguien podría explicar esto en el contexto del conjunto de compiladores de g ++?


Esto se define en 15.1 Lanzar una excepción del estándar.

El lanzamiento crea un objeto temporal.
Cómo se asigna la memoria para este objeto temporal no está especificado.

Después de la creación del objeto temporal, el control pasa al manejador más cercano en la pila de llamadas. desenrollando la pila entre el tiro y el punto de atrapada. A medida que la pila se desenrolla, las variables de la pila se destruyen en orden inverso a la creación.

A menos que se vuelva a lanzar la excepción, el temporal se destruye al final del controlador donde fue capturado.

Nota: Si captura por referencia, la referencia se referirá a la temporal. Si captura por valor, el objeto temporal se copia en el valor (y por lo tanto requiere un constructor de copia).

Consejo de S.Meyers (Catch by const reference).

try { // do stuff } catch(MyException const& x) { } catch(std::exception const& x) { }


Las implementaciones pueden diferir, pero hay algunas ideas básicas que se derivan de los requisitos.

El objeto de excepción en sí mismo es un objeto creado en una función, destruido en una persona que llama. Por lo tanto, normalmente no es factible crear el objeto en la pila. Por otro lado, muchos objetos de excepción no son muy grandes. Ergo, uno puede crear, por ejemplo, un búfer de 32 bytes y desbordamiento para acumular si realmente se necesita un objeto de excepción más grande.

En cuanto a la transferencia real de control, existen dos estrategias. Una es registrar suficiente información en la pila para desenrollar la pila. Esto es básicamente una lista de destructores para ejecutar y manejadores de excepciones que pueden atrapar la excepción. Cuando ocurre una excepción, ejecuta la pila que ejecuta esos destructores hasta que encuentres una captura coincidente.

La segunda estrategia mueve esta información a tablas fuera de la pila. Ahora, cuando ocurre una excepción, la pila de llamadas se usa para descubrir qué ámbitos se ingresan pero no se salen. Luego se busca en las tablas estáticas para determinar dónde se manejará la excepción lanzada y qué destructores se ejecutarán en el medio. Esto significa que hay menos gastos generales de excepción en la pila; las direcciones de retorno son necesarias de todos modos. Las tablas son datos adicionales, pero el compilador puede ponerlos en un segmento cargado de demanda del programa.


Puede echar un vistazo Article para una explicación detallada.

También puede ser útil echar un vistazo a un truco utilizado en la C simple para implementar algún tipo de manejo de excepciones básico. Esto implica el uso de setjmp () y longjmp () de la siguiente manera: el primero guarda la pila para marcar el manejador de excepciones (como "catch"), mientras que el último se usa para "lanzar" un valor. El valor "arrojado" se ve como si hubiera sido devuelto desde una función llamada. El "bloque try" finaliza cuando se llama de nuevo a setjmp () o cuando la función retorna.