Правда об оверхеде исключений.
От: gear nuke  
Дата: 14.07.08 06:03
Оценка: 35 (9)
Навеяно, например, Re: пример из книги: цикл + try/catch
Автор: Clevelus
Дата: 13.07.08
. Не буду затрагивать высокоуровневые вещи, флейм vc коды возврата, и TR 18015.

Рассмотрим 2 примера для самого плохого случая из промышленных компиляторов — MSVC x86 (32bit).

void foo(const string&);

void test_eh1(const vector<string> & v)
{
  try
  {
    for ( vector<string>::const_iterator i = v.cbegin(); i != v.cend(); ++i )
      foo(*i);
  }
  catch(...)
  {
    __asm int 3
  }
}

void test_eh2(const vector<string> & v)
{
  for ( vector<string>::const_iterator i = v.cbegin(); i != v.cend(); ++i )
  {
    try
    {
      foo(*i);
    }
    catch(...)
    {
      __asm int 3
    }
  }
}


Вот что создаёт компилятор, инструкции для поддержки C++ EH выделены:

_TEXT   SEGMENT
__$EHRec$ = -16                     ; size = 16
_v$ = 8                         ; size = 4
?test_eh1@@YGXABV?$vector@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@2@@std@@@Z PROC ; test_eh1, COMDAT

; 62   : {

    push    ebp
    mov ebp, esp
    push    -1 ; состояние для обработчика SEH
    ;; установка SEH фрейма OS - регистрируется обработчик понимающий C++ исключения 
    push    __ehhandler$?test_eh1@@YGXABV?$vector@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@2@@std@@@Z
    mov eax, DWORD PTR fs:0
    push    eax
    mov DWORD PTR fs:0, esp
    push    ecx
    push    ebx
    push    esi
    push    edi

; 63   :   try
; 64   :   {
; 65   :     for ( vector<string>::const_iterator i = v.cbegin(); i != v.cend(); ++i )

    mov edi, DWORD PTR _v$[ebp]
    mov esi, DWORD PTR [edi]
    mov DWORD PTR __$EHRec$[ebp], esp
    mov DWORD PTR __$EHRec$[ebp+12], 0 ; состояние для обработчика SEH
    npad    5
$LL3@test_eh1:
    cmp esi, DWORD PTR [edi+4]
    je  SHORT $LN10@test_eh1

; 66   :       foo(*i);

    push    esi
    call    ?foo@@YGXABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z ; foo
    add esi, 16                 ; 00000010H
    jmp SHORT $LL3@test_eh1
__catch$?test_eh1@@YGXABV?$vector@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@2@@std@@@Z$0:

; 67   :   }
; 68   :   catch(...)
; 69   :   {
; 70   :     __asm int 3

    int 3

; 71   :   }

    mov eax, $LN10@test_eh1
    ret 0
$LN10@test_eh1:

; 72   : }

    mov ecx, DWORD PTR __$EHRec$[ebp+4] ;; снатие SEH frame 
    pop edi
    pop esi
    mov DWORD PTR fs:0, ecx             ;;
    pop ebx
    mov esp, ebp
    pop ebp
    ret 4
_TEXT   ENDS


_TEXT   SEGMENT
_i$21988 = -20                      ; size = 4
__$EHRec$ = -16                     ; size = 16
_v$ = 8                         ; size = 4
?test_eh2@@YGXABV?$vector@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@2@@std@@@Z PROC ; test_eh2, COMDAT

; 75   : {

    push    ebp
    mov ebp, esp
    push    -1
    push    __ehhandler$?test_eh2@@YGXABV?$vector@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@2@@std@@@Z
    mov eax, DWORD PTR fs:0
    push    eax
    mov DWORD PTR fs:0, esp
    sub esp, 8

; 76   :   for ( vector<string>::const_iterator i = v.cbegin(); i != v.cend(); ++i )

    mov eax, DWORD PTR _v$[ebp]
    push    ebx
    push    esi
    mov esi, DWORD PTR [eax]
    push    edi
    mov DWORD PTR __$EHRec$[ebp], esp
$LN23@test_eh2:
    mov ecx, DWORD PTR _v$[ebp]
    mov DWORD PTR _i$21988[ebp], esi
    cmp esi, DWORD PTR [ecx+4]
    je  SHORT $LN2@test_eh2

; 77   :   {
; 78   :     try
; 79   :     {
; 80   :       foo(*i);

    push    esi
    mov DWORD PTR __$EHRec$[ebp+12], 0
    call    ?foo@@YGXABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z ; foo
    mov DWORD PTR __$EHRec$[ebp+12], -1

; 76   :   for ( vector<string>::const_iterator i = v.cbegin(); i != v.cend(); ++i )

    add esi, 16                 ; 00000010H
    jmp SHORT $LN23@test_eh2
__catch$?test_eh2@@YGXABV?$vector@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@2@@std@@@Z$0:

; 81   :     }
; 82   :     catch(...)
; 83   :     {
; 84   :       __asm int 3

    int 3

; 85   :     }

    mov DWORD PTR __$EHRec$[ebp+12], -1
    mov eax, $LN21@test_eh2
    ret 0
$LN21@test_eh2:
    mov esi, DWORD PTR _i$21988[ebp]
    add esi, 16                 ; 00000010H
    jmp SHORT $LN23@test_eh2
$LN2@test_eh2:

; 86   :   }
; 87   : }

    mov ecx, DWORD PTR __$EHRec$[ebp+4]
    pop edi
    pop esi
    mov DWORD PTR fs:0, ecx
    pop ebx
    mov esp, ebp
    pop ebp
    ret 4
_TEXT   ENDS


Если откинуть мусор, останется соль — команды вида
mov DWORD PTR __$EHRec$[ebp+12], 0
mov DWORD PTR __$EHRec$[ebp+12], -1

Это неявно вводимая компилятором переменная (типа ehstate) — состояние, по которому, в случае выброса исключения, обработчик определит, где оно произошло. "Оверхед" от этих команд очень мал по сравнению, например, с вызовом функции — на скорости цикла не скажется.

SEH фрейм регистрируется один раз — в прологе и снимается один раз — в эпилоге функции. В этом примере не видно, но можете проверять сами — картина останется неизменной независимо от количества вложенных try catch блоков. Будет лишь меняться значение ehstate — по сути, уровень вложенности. Если интересно, как работает обработчик, можно почитать статью Matt Pitreck в MSDN (есть перевод на wasm.ru) об обработке обычных (SEH) исключений компилятором MSVC. C++ EH работает примерно так же, только структура на стеке чуть меньше

Из принципиальных отличий от кода без исключений, я бы выделил невозможность инлайна:
1. дестракторов объектов из try блока;
2. самих функций с try блоком.
но тут еще вопрос, является ли это оверхедом, учитывая, что функция вызывается более одного раза...


Вывод такой — не стоит забивать голову ерундой об оверхеде. Нужно быть очень увереннымв себе, что бы писать под Win даже без __try __except, а C++ EH лишнего практически не вносит. Разве что копирование выброшенного объекта, если используется в обработчике (кстати, при ловле по ссылке — будет скопирована "ссылка"). А в x64 битной Win и SEH бесплатен.
People who are more than casually interested in computers should have at least some idea of what the underlying hardware is like. Otherwise the programs they write will be pretty weird (c) D.Knuth
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.