我知道当某件事是thrown时,堆栈被“展开”到它被捕获的程度,每个函数上下文中堆栈上的类实例的析构函数都会运行(这就是为什么你不应该从析构函数中抛出异常--你可能会抛出第二个异常)...but我想知道当这种情况发生时,我抛出的对象在内存中存储在哪里?
它依赖于实现吗?如果是这样的话,有没有被大多数流行的编译器使用的特殊方法?
发布于 2011-07-07 22:14:29
是的,答案取决于编译器。
使用我的编译器(g++ 4.4.3)进行的快速实验显示,它的运行时库首先尝试为异常分配malloc内存,如果失败,则尝试在驻留在数据段上的进程范围内的“紧急缓冲区”中分配空间。如果这不起作用,它将调用std::terminate()。
紧急缓冲区的主要用途似乎是能够在进程用完堆空间后抛出std::bad_alloc (在这种情况下,malloc调用将失败)。
相关函数为__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));
}我不知道这个计划有多典型。
发布于 2011-07-07 22:19:46
C++标准通常指定语言的行为方式,但不指定编译器应该如何实现该行为。我认为这个问题就属于这一类。实现这样的东西的最佳方式取决于机器的具体情况--有些处理器有很多通用寄存器,有些处理器只有很少的寄存器。甚至可以使用专门的异常寄存器来构建处理器,在这种情况下,编译器应该可以自由地利用该特性。
发布于 2011-07-07 22:22:53
嗯,它不能在堆栈上,因为它将被展开,它不能在堆上,因为这意味着系统可能不会抛出std::bad_alloc。除此之外,这完全取决于实现:不指定实现(必须记录),但不指定。(实现可以在大多数时间使用堆,只要它有某种紧急备份,即使在没有更多内存的情况下也允许有限数量的异常。)
https://stackoverflow.com/questions/6611880
复制相似问题