异常处理时类型识别的工作原理

时间:2016-11-30 09:20:05

标签: c++ exception exception-handling

c ++代码中的某处:

0x0100

try { foo(); } catch (const FooExceptionOne& e) { // ... } catch (const FooExceptionTwo& e) { // ... } catch (const std::exception& e) { // ... } FooExceptionOne是从FooExceptionTwo派生的自定义类。

在抛出异常的那一刻;类型识别如何工作?它是某种动态铸造还是plymorphism,发生在“引擎盖下”?

我的第一个想法是动态投射,但(当然)它似乎是非常缓慢的解决方案。

2 个答案:

答案 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 internalsException Handling in LLVM

编译器将生成带有异常typeinfo的数组/表,以便try / catch进行搜索。