c ++代码中的某处:
0x0100
try
{
foo();
}
catch (const FooExceptionOne& e)
{
// ...
}
catch (const FooExceptionTwo& e)
{
// ...
}
catch (const std::exception& e)
{
// ...
}
和FooExceptionOne
是从FooExceptionTwo
派生的自定义类。
在抛出异常的那一刻;类型识别如何工作?它是某种动态铸造还是plymorphism,发生在“引擎盖下”?
我的第一个想法是动态投射,但(当然)它似乎是非常缓慢的解决方案。
答案 0 :(得分:5)
GCC,Clang和英特尔C ++编译器将该类型推送到寄存器中,如本页所示:https://godbolt.org/g/w0lD0p
代码:
switch (throwType) {
case 0:
throw 0;
case 1:
throw 0.0;
case 2:
throw "test";
}
在GCC中编译为以下汇编代码:
.L17:
mov edi, 4
call __cxa_allocate_exception
xor edx, edx
mov DWORD PTR [rax], 0
mov esi, OFFSET FLAT:typeinfo for int
mov rdi, rax
call __cxa_throw
.L4:
mov edi, 8
call __cxa_allocate_exception
xor edx, edx
mov QWORD PTR [rax], OFFSET FLAT:.LC1
mov esi, OFFSET FLAT:typeinfo for char const*
mov rdi, rax
call __cxa_throw
.L3:
mov edi, 8
call __cxa_allocate_exception
xor edx, edx
mov QWORD PTR [rax], 0x000000000
mov esi, OFFSET FLAT:typeinfo for double
mov rdi, rax
call __cxa_throw
从行中可以看出:
mov esi, OFFSET FLAT:typeinfo for int
mov esi, OFFSET FLAT:typeinfo for char const*
mov esi, OFFSET FLAT:typeinfo for double
该类型的typeinfo存储在esi
寄存器中的GCC中。然而,这是特定于编译器的,因此虽然GCC(以及Clang和Intel)也是如此,但它可能不适用于任何其他编译器(Borland等)。
throw
使用的类型信息可以在编译时完全确定,因此不需要使用C ++的RTTI功能,因为它基本上是类型ids的枚举,用于映射到相应的捕获块。
确定类型映射方式的规则可以在标准的第15.3节中找到,关于处理异常。
答案 1 :(得分:0)
查看以下文章C++ exception handling internals和Exception Handling in LLVM。
编译器将生成带有异常typeinfo的数组/表,以便try / catch进行搜索。