Yo entiendo que cuando algo es throw
n, la pila está 'desprendido' hasta el punto donde es capturado, y los destructores de instancias de la clase en la pila en cada función del contexto de ejecución (que es por qué usted no debe lanzar una excepción de un destructor - usted podría terminar encima de lanzar un segundo)...pero me pregunto donde en la memoria el objeto de que he tirado es almacenado mientras esto sucede?
Es que depende de la implementación? Si es así, ¿hay un método particular utilizado por la mayoría de los compiladores populares?
Respuestas
¿Demasiados anuncios?Sí, la respuesta es compilador-dependiente.
Un experimento rápido con mi compilador (g++ 4.4.3
), revela que su biblioteca de tiempo de ejecución primer lugar, intenta malloc
memoria de la excepción, y, en su defecto, los intentos de asignar espacio dentro de un proceso de "emergencia buffer" que vive en el segmento de datos. Si eso no funciona, llama a std::terminate()
.
Parecería que el principal propósito de la emergencia de búfer es ser capaz de tirar std::bad_alloc
después de que el proceso se ha agotado el espacio de montón (en cuyo caso el malloc
de llamada de fallar).
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é cómo típico de este esquema es.
Desde esta página:
El almacenamiento es necesario para excepciones de tirado. Este almacenamiento se debe conservar mientras que la pila está en fase de desenrollado, ya que será utilizada por el controlador, y debe ser seguro para subprocesos. Objeto de excepción almacenamiento será, por tanto, normalmente se asignados en el montón, aunque las implementaciones pueden proporcionar un emergencia de búfer para apoyar a tirar bad_alloc excepciones en virtud de memoria baja condiciones.
Ahora, esto es sólo el Itanium ABI y estoy en busca de detalles específicos de GCC, Clang y MSVC. Sin embargo, el estándar no especifica nada y esta parece ser la forma más obvia de aplicar la excepción de almacenamiento, así que...
No sé si esto va a responder a su pregunta, pero esto (Cómo compilador de C implementa la gestión de excepciones) es excelente artículo sobre el manejo de excepciones en absoluto:. Lo recomiendo encarecidamente (:
Lo siento por la respuesta corta, pero toda la información en el artículo es grande, no puedo recoger y publicar alguna información aquí.
El estándar de C generalmente especifica cómo el lenguaje se comporta, pero no cómo el compilador debe aplicar ese comportamiento. Creo que esta cuestión 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 un montón de registros de propósito general, algunas tienen muy pocos. Un procesador incluso podría ser construido con un registro especial para las excepciones, en cuyo caso el compilador debe ser libre de tomar ventaja de esta característica.
Bien, no puede ser en la pila, ya que va a ser desenrollado, y no puede ser en el montón, ya que significaría que el sistema probablemente no podía tirar std::bad_alloc
. Aparte de eso, es totalmente de la aplicación: no es de aplicación especifica (que debe ser documentado), pero sin especificar. (Una aplicación podría utilizar el montón de la mayoría de las veces, como siempre que tiene algún tipo de emergencia que permitirá un número limitado de excepciones, incluso cuando no hay más memoria).