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

Dan*_*nyX 3 c++ exception-handling exception

在c ++代码中的某处:

try 
{
   foo();
}
catch (const FooExceptionOne& e) 
{
    // ...
}
catch (const FooExceptionTwo& e) 
{
    // ...
}
catch (const std::exception& e) 
{
    // ...
}
Run Code Online (Sandbox Code Playgroud)

FooExceptionOne并且FooExceptionTwo是从中派生的自定义类std::exception.

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

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

Tom*_*sen 5

GCC,Clang和英特尔C++编译器将类型推送到寄存器,如本页所示:https://godbolt.org/g/w0lD0p

代码:

switch (throwType) {
  case 0:
    throw 0;

  case 1:
    throw 0.0;

  case 2:
    throw "test";
}
Run Code Online (Sandbox Code Playgroud)

在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
Run Code Online (Sandbox Code Playgroud)

从行中可以看出:

mov     esi, OFFSET FLAT:typeinfo for int
mov     esi, OFFSET FLAT:typeinfo for char const*
mov     esi, OFFSET FLAT:typeinfo for double
Run Code Online (Sandbox Code Playgroud)

该类型的typeinfo存储在esi寄存器中的GCC中.然而,这是特定于编译器的,因此虽然GCC(以及Clang和Intel)也是如此,但它可能不适用于任何其他编译器(Borland等).

使用的类型信息throw可以在编译时完全确定,因此不需要使用C++的RTTI特性,因为它基本上是类型ids的枚举,用于映射到相应的catch块.

确定类型映射方式的规则可以在标准的第15.3节中找到,关于处理异常.