Entiendo que cuando algo es throw
n, la pila se 'desenrolla' hasta el punto en que se captura, y se ejecutan los destructores de las instancias de clase en la pila en cada contexto de función (por lo que no debe lanzar una excepción de un destructor - podrías acabar tirando una segunda) ... pero me pregunto dónde en la memoria se almacena el objeto que he tirado mientras esto sucede.
¿Depende de la implementación? Si es así, ¿existe algún método en particular utilizado por los compiladores más populares?
c++
exception
exception-handling
sje397
fuente
fuente
raise
), destrúyalo. El problema con la asignación de montón es, ¿qué debe hacer si falla su intento de asignar la excepción? Tendría que abortar (como lo haría con el desbordamiento de la pila si al ponerlo en la pila "falla" debido a la falta de espacio). A diferencia de Java, la implementación no puede lanzar una excepción diferente.Respuestas:
Sí, la respuesta depende del compilador.
Un experimento rápido con mi compilador (
g++ 4.4.3
) revela que su biblioteca de tiempo de ejecución primero intentamalloc
memorizar la excepción y, en su defecto, intenta asignar espacio dentro de un "búfer de emergencia" de todo el proceso que vive en el segmento de datos. Si eso no funciona, llamastd::terminate()
.Parece que el propósito principal del búfer de emergencia es poder lanzar
std::bad_alloc
después de que el proceso se haya quedado sin espacio de almacenamiento dinámico (en cuyo caso lamalloc
llamada fallaría).La función relevante es
__cxa_allocate_exception
:extern "C" void * __cxxabiv1::__cxa_allocate_exception(std::size_t thrown_size) throw() { void *ret; thrown_size += sizeof (__cxa_refcounted_exception); ret = malloc (thrown_size); if (! ret) { __gnu_cxx::__scoped_lock sentry(emergency_mutex); bitmask_type used = emergency_used; unsigned int which = 0; if (thrown_size > EMERGENCY_OBJ_SIZE) goto failed; while (used & 1) { used >>= 1; if (++which >= EMERGENCY_OBJ_COUNT) goto failed; } emergency_used |= (bitmask_type)1 << which; ret = &emergency_buffer[which][0]; failed:; if (!ret) std::terminate (); } // We have an uncaught exception as soon as we allocate memory. This // yields uncaught_exception() true during the copy-constructor that // initializes the exception object. See Issue 475. __cxa_eh_globals *globals = __cxa_get_globals (); globals->uncaughtExceptions += 1; memset (ret, 0, sizeof (__cxa_refcounted_exception)); return (void *)((char *)ret + sizeof (__cxa_refcounted_exception)); }
No sé qué tan típico es este esquema.
fuente
malloc
llamada fallaría" bien, normalmente, pero no necesariamente.De esta pagina :
Ahora, esto es solo el Itanium ABI y estoy buscando detalles específicos para GCC, Clang y MSVC. Sin embargo, el estándar no especifica nada y esta parece ser la forma obvia de implementar el almacenamiento de excepciones, así que ...
fuente
No sé si esto responderá a su pregunta, pero este (Cómo un compilador de C ++ implementa el manejo de excepciones) es un excelente artículo sobre el manejo de excepciones:. Lo recomiendo altamente (:
Lo siento por la respuesta corta, pero toda la información del artículo es excelente, no puedo elegir y publicar información aquí.
fuente
excpt_info
en esa página, le da información sobre cómo lo hace MSVC.El estándar C ++ generalmente especifica cómo se comporta el lenguaje pero no cómo el compilador debe implementar ese comportamiento. Creo que esta pregunta entra en esa categoría. La mejor manera de implementar algo como esto depende de las características específicas de la máquina: algunos procesadores tienen muchos registros de propósito general, algunos tienen muy pocos. Incluso se podría construir un procesador con un registro especial solo para excepciones, en cuyo caso el compilador debería tener la libertad de aprovechar esa característica.
fuente
Bueno, no puede estar en la pila, ya que se va a deshacer, y no puede estar en el montón, ya que eso significaría que el sistema probablemente no podría lanzar
std::bad_alloc
. Aparte de eso, depende completamente de la implementación: no se especifica la implementación (que debe estar documentada), pero no se especifica. (Una implementación podría usar el montón la mayor parte del tiempo, siempre que tenga algún tipo de respaldo de emergencia que permita un número limitado de excepciones incluso cuando no haya más memoria).fuente
std::bad_alloc
que funcione. Esto significa que una implementación no puede usar sistemáticamente el montón. El estándar no lo permite. Baso mis afirmaciones en el estándar.