当抛出异常时,堆栈展开将被启动,直到遇到处理代码,但我对整个过程的机制有点不清楚。
1-异常存储在哪里?我不是指实际的异常对象,它可能很大,例如有一个消息字符串或其他什么,但实际引用或指针,如果你愿意的话。它必须是一个统一的存储位置,这样它才能在堆栈展开并到达处理位置时存活下来?
2-程序流如何确定是否必须展开特定的功能框架并调用与程序计数器相关联的相应析构函数以指示位置或在其进一步展开之前寻求异常处理?
3-如何实际检查抛出的和正在发生的异常?
我知道答案可能包括特定于平台的内容,在这种情况下,我们将对此表示赞赏。不过,不需要超越x86/x64和ARM。
发布于 2014-10-30 12:56:39
这些都是实现细节,将在设计异常处理机制的(非平凡的)过程中决定。我只能给出一个草图,说明一个人如何(或不可能)选择实现这一点。
如果您想详细描述一个实现,可以阅读GCC和其他流行编译器使用的Itanium ABI规范。
1-异常对象存储在未指定的位置,该位置必须持续到异常已被处理为止。指针或引用像任何其他变量一样在异常处理代码中传递,然后通过类似于传递函数参数的机制传递给处理程序(如果它接受引用)。
2-有两种常见的方法:静态数据结构将程序的位置映射到堆栈框架的信息;或动态的类似堆栈的数据结构,包含需要销毁的活动处理程序和重要堆栈对象的信息。
在第一种情况下,在抛出该信息时,它将查看是否存在要销毁的本地对象和任何本地处理程序;如果没有,它将在本地堆栈帧上找到函数返回地址,并对调用函数的堆栈帧应用相同的进程,直到找到处理程序为止。一旦找到处理程序,CPU寄存器将被更新以引用该堆栈帧,程序可以跳转到处理程序的代码。
在第二种情况下,它将弹出堆栈结构中的条目,使用它们告诉它如何销毁堆栈对象,直到找到合适的处理程序为止。一旦找到了处理程序,并且所有未打开的堆栈对象都被销毁,它就可以使用longjmp或类似的机制跳转到处理程序。
其他办法也是可能的。
3-异常处理代码将使用某种数据结构来标识类型,允许它将抛出的类型与处理程序的类型进行比较。由于继承,这有点复杂;测试不能是一个简单的比较。我不知道任何具体实现的细节。
发布于 2014-10-30 13:14:54
资料来源:异常如何(幕后)在c++中工作 (我阅读了大会并以我所理解的方式回答了问题)。
问题1#:
movl $1, (%esp)
call __cxa_allocate_exception
movl $_ZN11MyExceptionD1Ev, 8(%esp)
movl $_ZTI11MyException, 4(%esp)_ZTI11MyException是例外。它看起来好像有自己的分配,而不是在堆栈中,它将指针放置在名为eax的寄存器中。
问题2#:
.LFE9:
.size _Z20my_catching_functionv, .-_Z20my_catching_functionv
.section .gcc_except_table,"a",@progbits
.align 4它看起来像存储在程序中静态数据中的表。这样它就能知道它能抓到哪里了。没有任何关于对象在解压帧后如何自毁的信息,所以这是来自Visual的:(顶部的链接来自Linux)
MyClass s, s2, s3, s4;
mov dword ptr [ebp-4],3
try {
{
MyClass s, s2, s3, s4;
mov byte ptr [ebp-4],7
}看起来它节省了要销毁的物体的数量。例如,当它完成时:
call MyClass::~MyClass (0DC1163h)
mov dword ptr [ebp-4],0FFFFFFFFh0FFFFFFFFh的意思是没什么可以毁灭的。如果我发现了一些关于它是如何发现和摧毁它们的东西,我会在这里添加。
问题3#:
和前面的问题一样,你看到了它的表,它可以知道它在正确的函数中是什么。
https://stackoverflow.com/questions/26652963
复制相似问题