На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
Модераторы: Qraizer, Hsilgos
  
> Исключения и производительность , практика
    Очень много писалось и говорилось об исключениях и производительности, но время бежит, а мощности ростут, компиляторы и язык совершенствуются.
    Как уменьшить потери при использовании исключений? Возможно ли? Интересует в первую очередь практическая сторона. Возможно кто-то уже решал подобные задачи, проводил тесты и т.д. Может кому-то пришлось отказаться от исключений вовсе?
    Хотелось бы обсудить (именно обсудить, а не разводить очередной холивар) все возможные решения проблемы.
      Сейчас сам пишу 3D графический движок, отказался от исключений вообще, производительность снижается заметно, гораздо лучше использовать возвращаемые значения о состоянии выпонения функции. Сам довольно мало испытывал исключения, так как я любитель наиболее оптимального кода и стараюсь использовать вставки на асемблере по максимуму (если это не очень сильно снижает скорость разработки программы).
        x0ras
        Исключения, конечно, снижают производительность. Но не нужно забывать о том, что исключения, в идеале, должны возникать не слишком часто. А если исключения не использовать, то придется каждый вызов функции обрамлять операторами проверки возвращаемого значения, причем эти операторы будут работать всегда, а исключение только во время возникновения ошибки. Так что иногда исключения могут оказаться быстрее, чем проверки возвращаемого значения. Ну, а про читабельность кода я уже не говорю...
          Цитата artalex @
          Так что иногда исключения могут оказаться быстрее, чем проверки возвращаемого значения.

          не могут. сколько раз писалось, даже если они не возникают, они тормозят прогу.
            Цитата Sazabis @
            Цитата (artalex @ Сегодня, 17:23)
            Так что иногда исключения могут оказаться быстрее, чем проверки возвращаемого значения.
            не могут. сколько раз писалось, даже если они не возникают, они тормозят прогу.

            Чем? При каком компиляторе?
              Давайте по порядку.

              1) если исключения не возникают, то прога практически не тормозится
              2) исключения В ЛЮБОМ СЛУЧАЕ будут медленне нежели обычная проверка возвращаемого значения. х0ras-а интересует, как повысить производительность. Ответ - практически никак. Писать свои исключения, менеджеры памяти и т.д. Это связано прежде всего с кодом, который генерируется для "отката". В теневой стек должны быть записаны адреса объектов, которые должны быть разрушены при ненормальной раскрутке. Это процесс довольно быстрый, но он в любом случае занимает ненулевое время.
              3) раскрутка стека. Само исключение так же живёт не в стеке (хотя бывает, и живёт, в отдельных реализациях), чаще всего они лежат либо в теневом стеке, либо в куче. А с ними операции тоже не самые быстрые.
              4) исключения - это шаг, на который можно и нужно идти, по крайней мере, на этапе отладки. Нп, написать что нибудь типа функций/макросов check_value(), которые в релиз версии должны быть заменены на пустые значения.
              5) проверка возвращаемых значений - это прекрасно, т.к. быстрее неё ничего не будет. Но... они хороши в индивидуальной разработке. Когда ты реально можешь грамотно и польностью протестировать весь написаный код. В коммандной разработке часто используются подобные check_value.
                Если говорить о программировании под Windows, то там обработка исключений настолько встроена в систему ( SEH ), что 1) гарантируется минимум накладных расходов, 2)даже если вы сами не используете исключения, определённые структуры для их обработки всё равно поддерживаются. Всё равно в TEB каждого thread-а есть EXCEPTION_REGISTRATION - список обработчиков исключений. Когда вы пишите __try/__except или try/catch, то компилятор создаёт на стеке структуру EXCEPTION_REGISTRATION и добавляет ваш обработчик в список. Таким образом, при использовании исключений у вас чуть увеличивается объём использованного стека и добавляется пара ассемблерных команд в духе
                ExpandedWrap disabled
                  _asm move fs[off_EXCEPTION_REGISTRATION], handler_addr

                Моё утверждение следующее: пока не происходит исключение, почти нет потери производительности. Практический пример - видела тысячу и одну рекоммендацию драйверистам касательно использования SEH-а, а вряд ли кто станет возражать, что в драйвере, да ещё в обработчиках ISR-ов, время является весьма критичным ресурсом.
                Возможно, я некорректно понимаю, и в данной теме под использованием механизма исключений подразумевалась не обработка экстренных ситуаций и не разовые переходы ( как-то при завершении программы ), а именно регулярное использование исключений для передачи управления на другой уровень программы?
                  Цитата Lucifer @
                  Чем? При каком компиляторе?

                  компилятор не важен, а чем, тут уже лучше меня написли.
                  сдаеться мне, автор и сам понимает это.
                  Цитата x0ras @
                  Как уменьшить потери при использовании исключений?


                  Вопрос в скорости, позволят ли современные машины обрабатывать код с исключениями быстро ? Тут уже дело перформенс тестов: допустимо такое время или нет. А потери всегда будут равноценными, при наличии одного кол-ва обработчиков, для ветви кода <- имхо. Или есть другие мнения ?
                    Цитата TrefptYc @
                    Если говорить о программировании под Windows, то там обработка исключений настолько встроена в систему ( SEH ), что 1) гарантируется минимум накладных расходов, 2)даже если вы сами не используете исключения, определённые структуры для их обработки всё равно поддерживаются.

                    Проблема в другом - это не C++-ные исключения. А потому при их выстреливании никаких побочных эффектов, гарантированных для исключений С++ (как то раскрутка стека, вызов деструкторов и т. п.) не происходит.
                      Цитата Flex Ferrum @
                      Проблема в другом - это не C++-ные исключения. А потому при их выстреливании никаких побочных эффектов, гарантированных для исключений С++ (как то раскрутка стека, вызов деструкторов и т. п.) не происходит.

                      Позвольте, позвольте!
                      Выдержка из одной из статей Мэтта Питрика (Matt Pietrek) касательно SEH.
                      Цитата
                      I'm going to avoid the issue of true C++ exception handling, which uses catch() instead of _except. Under the hood, true C++ exception handling is implemented very similarly to what I'll describe here


                      И как это нет раскрутки стека или деструкторов? А если обработчик вызывается с флагом EH_UNWINDING
                      Цитата
                      What does EH_UNWINDING mean? When an exception callback is invoked with the EH_UNWINDING flag, the operating system is giving the handler function an opportunity to do any cleanup it needs to do. What sort of cleanup? A perfect example is that of a C++ class destructor. When a function's exception handler declines to handle an exception, control typically doesn't exit from that function in a normal manner. Now, consider a function with a C++ class declared as a local variable. The C++ specification says that the destructor must be called. The exception handler callback with the EH_UNWINDING flag is the opportunity for the function to do cleanup work such as invoking destructors and _finally blocks.
                        Цитата TrefptYc @
                        И как это нет раскрутки стека или деструкторов? А если обработчик вызывается с флагом EH_UNWINDING

                        Ну, значит я отстал от жизни.
                          В SEH в Win32 ЕСТЬ раскрутка стека... Компилятор MSVC++ даже стандартные исключения С++ (throw, catch) преобразует в вызовы _try, _except. З.Ы. я точно не помню, как именно, надо перечитать Джеффри Рихтера :P
                            Что значит, обработка исключений встроена в систему? И как это может отражаться на производительности?

                            Если
                            а) исключительная ситуации в программе перехватывается операционной системой, то даже не знаю как из этой ситуации выбираться, так как выглядит она совершенно неуправляемой;
                            б) при возникновении исключительной ситуации программа выполняет системный вызов для размотки стека, тогда вижу две основные проблемы: первая, системный вызов - это неизбежная потеря времени, при том что ОС не может выполнить связанную с ситуацией работу быстрее, чем сама программа; вторая, в ОС вынужденно встраиваются обработчики исключительных ситуаций всех языков, допускающих обработку исключений, что увеличивает её размер и делает её ещё неповоротливей.
                            в) система обнаруживает исключительные ситуации во время системных вызовов и предупреждает о них вызывающую программу, что позволяет последней адекватно реагировать на ошибки, ну это делали все операционные системы, чуть ли не с момента появления самого понятия "операционная система". Или к разработчикам Windows эта очевидная мысль пришла только сейчас?
                            В DOS такой механизм действовал.
                            г) система позволяет выбрасывать исключения из Callback-функций, корректно обрабатывая их. Идея выглядит здраво, но по некотором размышлении её придётся ограничить, чтобы выбрасывать можно было определённое множество исключений.

                            Таким образом определённо бракуются а и б, нормально поддерживается в и частично г.
                            Лично я стараюсь избегать исключений, анализируя ситуацию заранее. Если например я знаю, что функция не обрабатывает отрицательных параметров, то для обработки их создаю альтернативную ветку, а не перехватываю исключение, даже если оно из неё выбрасывается.
                              Цитата
                              Что значит, обработка исключений встроена в систему? И как это может отражаться на производительности?

                              Обработка исключений встроена в систему значит то, что система берет на себя обязанность (или часть обязанности) по раскрутке стека. Также система рпедоставляет функции для программного выкидывания исключений.

                              Цитата
                              а) исключительная ситуации в программе перехватывается операционной системой, то даже не знаю как из этой ситуации выбираться, так как выглядит она совершенно неуправляемой;

                              Именно операционной системой она и перехватывается. По крайней мере для аппаратных исключений. Аппаратные исключения по сути есть прерывания процессора. Подозреваю, что и программные исключения тоже могут ими являться, хотя могут просто вызываться соответствующие обработчики.

                              Цитата
                              Когда вы пишите __try/__except или try/catch, то компилятор создаёт на стеке структуру EXCEPTION_REGISTRATION и добавляет ваш обработчик в список. Таким образом, при использовании исключений у вас чуть увеличивается объём использованного стека и добавляется пара ассемблерных команд в духе

                              :yes:
                              А если учесть, что во всей программе всего несколько блоков try/catch, то издержки несущественны. Более того, обычно программа без использования исключений строится следующим способом:
                              ExpandedWrap disabled
                                int f1_1() {
                                ...
                                }
                                 
                                int f1_2() {
                                ...
                                }
                                 
                                int f1_3() {
                                ...
                                }
                                 
                                int f2_1() {
                                if(!f1_1())
                                    // return error;
                                if(!f1_2())
                                    // return error;
                                if(!f1_3())
                                    // return error;
                                 
                                    ...
                                }
                                 
                                int f2_2() {
                                if(!f1_1())
                                    // return error;
                                if(!f1_2())
                                    // return error;
                                if(!f1_3())
                                    // return error;
                                 
                                    ...
                                }
                                 
                                int f() {
                                if(!f2_1()) {
                                   // return error;
                                if(!f2_2())
                                   // return error;
                                 
                                   ...
                                }

                              Суть в том, что у нас много вложенных вызовов (обычно "высокоуровневые" функции обращаются к функциям "более низкого уровня"), и в каждом случае значение проверяется с помощью if. Количество этих проверок несравнимо больше, чем количество блоков try/catch. При этом операция условного перехода заметно влияет на производительность (по сравнению с mov, например). При использовании исключений проверка ошибок с помощью if присутсвтует только на самом "нижнем" уровне. Остальным функциям в большинстве случаев это не требуется.

                              Далее, если всё-таки вываливается исключение. Тут говорить нечего, конечно это накладно по сравнению с проверкой условия. НО! После выброса исключения обычно задумываться о производительности не приходится. Исключения составляют, пожалуй, лишь программы, обслуживающие много пользователей, в ходе выполнения которых возникает нехватка системных ресурсов (памяти, например), и надо обеспечить остальным пользователям (которым хватило ресурсов) быстрое выполнение. Однако в таких случаях разумнее установить настраиваемое ограничение на количество пользователей/ресрусов, т. к. например Windows при нехватке памяти может просто убить процесс без всяких исключений.

                              Кроме того, используя аппаратные исключения SEH (ошибки доступа к памяти), можно нашаманить более быстрое приложение, которое работает с большими объемами данных (пример у Рихтера).
                                Вообще-то аппаратные исключения по стандарту языка C++ как бы и не совсем исключения. По крайней мере их перехват затруднён. Думаю часто хватило бы просто возможности оповестить программу о возникновении такой ситуации.
                                Раскрутка стека программы операционной системой затруднена хотя бы потому, что программа может использовать какую-то свой, не определённый в системе метод хранения необходимой информации. А так и получится, если программа строится компилятором/сборщиком сторонних фирм, а не создателя ОС. В случае с Windows это особенно актуально, так как MS известна своим пристрастием включать в свои ОС недокументированные возможности.
                                  Накладные расходы всегда появляются при использовании исключений во время выполнения программы, а не только при возникновении исключительных ситуаций. Я вижу смысл использовать исключения только в отладочной версии, т.к. в моем случае в релизе они бесполезны. Сейчас мне в голову приходит только одно решение - написать такой код, который бы в отладочной версии проводил проверки и выбрасывал/перехватывал исключения, а в релизе все проверки убивались.
                                    Цитата x0ras @
                                    Накладные расходы всегда появляются при использовании исключений во время выполнения программы, а не только при возникновении исключительных ситуаций. Я вижу смысл использовать исключения только в отладочной версии, т.к. в моем случае в релизе они бесполезны. Сейчас мне в голову приходит только одно решение - написать такой код, который бы в отладочной версии проводил проверки и выбрасывал/перехватывал исключения, а в релизе все проверки убивались.

                                    Насчёт накладных расходов. Решила наконец, что If in doubt, check it out
                                    Сравниваем.

                                    Проект без SEH
                                    ExpandedWrap disabled
                                      PUBLIC  _main
                                      PUBLIC  ??_C@_02DPKJAMEF@?$CFd?$AA@         ; `string'
                                      PUBLIC  ??_C@_0CJ@LGAHIOIG@should?5not?5be?5here?4?5Maybe?5zero?5d@ ; `string'
                                      EXTRN   _printf:NEAR
                                      EXTRN   _scanf:NEAR
                                      ;   COMDAT ??_C@_02DPKJAMEF@?$CFd?$AA@
                                      ; File d:\myprojects\4test\4test.cpp
                                      CONST   SEGMENT
                                      ??_C@_02DPKJAMEF@?$CFd?$AA@ DB '%d', 00H        ; `string'
                                      CONST   ENDS
                                      ;   COMDAT ??_C@_0CJ@LGAHIOIG@should?5not?5be?5here?4?5Maybe?5zero?5d@
                                      CONST   SEGMENT
                                      ??_C@_0CJ@LGAHIOIG@should?5not?5be?5here?4?5Maybe?5zero?5d@ DB 'should no'
                                          DB  't be here. Maybe zero division?', 00H  ; `string'
                                      ; Function compile flags: /Ogty
                                      CONST   ENDS
                                      ;   COMDAT _main
                                      _TEXT   SEGMENT
                                      _a$ = -4                        ; size = 4
                                      _main   PROC NEAR                   ; COMDAT
                                       
                                      ; 8    : {
                                       
                                          push    ecx
                                       
                                      ; 9    :     int a = 10;
                                      ; 10   :     a = 15;
                                      ; 11   :     a += 20;
                                      ; 12   :     a -= 40;
                                      ; 13   :     printf( "%d", a );
                                       
                                          push    -5                  ; fffffffbH
                                          push    OFFSET FLAT:??_C@_02DPKJAMEF@?$CFd?$AA@
                                          mov DWORD PTR _a$[esp+12], -5       ; fffffffbH
                                          call    _printf
                                       
                                      ; 14   :     scanf( "%d", &a );
                                       
                                          lea eax, DWORD PTR _a$[esp+12]
                                          push    eax
                                          push    OFFSET FLAT:??_C@_02DPKJAMEF@?$CFd?$AA@
                                          call    _scanf
                                       
                                      ; 15   :     if( a > 0 )
                                       
                                          mov eax, DWORD PTR _a$[esp+20]
                                          add esp, 16                 ; 00000010H
                                          test    eax, eax
                                          jle SHORT $L58684
                                       
                                      ; 16   :         printf( "should not be here. Maybe zero division?" );
                                       
                                          push    OFFSET FLAT:??_C@_0CJ@LGAHIOIG@should?5not?5be?5here?4?5Maybe?5zero?5d@
                                          call    _printf
                                          add esp, 4
                                      $L58684:
                                       
                                      ; 17   :     return 0;
                                       
                                          xor eax, eax
                                       
                                      ; 18   : }
                                       
                                          pop ecx
                                          ret 0
                                      _main   ENDP
                                      _TEXT   ENDS
                                      END



                                    А теперь c SEH( ветка, которая раньше была в обработчике IF вынесена в EXCEPT_HANDLER Проект скомпилирован с теми же стандартными настройками на VS .NET
                                    ExpandedWrap disabled
                                      PUBLIC  _main
                                      PUBLIC  ??_C@_02DPKJAMEF@?$CFd?$AA@         ; `string'
                                      PUBLIC  ??_C@_0CJ@LGAHIOIG@should?5not?5be?5here?4?5Maybe?5zero?5d@ ; `string'
                                      EXTRN   _printf:NEAR
                                      EXTRN   _scanf:NEAR
                                      EXTRN   __except_handler3:NEAR
                                      EXTRN   __except_list:DWORD
                                      ;   COMDAT CONST
                                      ; File d:\myprojects\4test\4test.cpp
                                      CONST   SEGMENT
                                      $T58689 DD  0ffffffffH
                                          DD  FLAT:$L58683
                                          DD  FLAT:$L58684
                                      CONST   ENDS
                                      ;   COMDAT ??_C@_02DPKJAMEF@?$CFd?$AA@
                                      CONST   SEGMENT
                                      ??_C@_02DPKJAMEF@?$CFd?$AA@ DB '%d', 00H        ; `string'
                                      CONST   ENDS
                                      ;   COMDAT ??_C@_0CJ@LGAHIOIG@should?5not?5be?5here?4?5Maybe?5zero?5d@
                                      CONST   SEGMENT
                                      ??_C@_0CJ@LGAHIOIG@should?5not?5be?5here?4?5Maybe?5zero?5d@ DB 'should no'
                                          DB  't be here. Maybe zero division?', 00H  ; `string'
                                      ; Function compile flags: /Ogty
                                      CONST   ENDS
                                      ;   COMDAT _main
                                      _TEXT   SEGMENT
                                      _a$ = -28                       ; size = 4
                                      [COLOR=red]__$SEHRec$ = -24 [/COLOR]                ; size = 24
                                      _main   PROC NEAR                   ; COMDAT
                                       
                                      ; 8    : {
                                       
                                      [COLOR=red] push    ebp
                                          mov ebp, esp
                                          push    -1
                                          push    OFFSET FLAT:$T58689
                                          push    OFFSET FLAT:__except_handler3
                                          mov eax, DWORD PTR fs:__except_list
                                          push    eax
                                          mov DWORD PTR fs:__except_list, esp
                                          sub esp, 12                 ; 0000000cH
                                          push    ebx
                                          push    esi
                                          push    edi
                                          mov DWORD PTR __$SEHRec$[ebp], esp[/COLOR]
                                      ; 9    :     int a = 10;
                                       
                                          mov DWORD PTR _a$[ebp], 10          ; 0000000aH
                                       
                                      ; 10   :     __try
                                       
                                          [COLOR=red]mov  DWORD PTR __$SEHRec$[ebp+20], 0[/COLOR]
                                       
                                      ; 11   :     {
                                      ; 12   :         a = 15;
                                       
                                          mov DWORD PTR _a$[ebp], 15          ; 0000000fH
                                       
                                      ; 13   :         a += 20;
                                       
                                          mov DWORD PTR _a$[ebp], 35          ; 00000023H
                                       
                                      ; 14   :         a -= 40;
                                       
                                          mov DWORD PTR _a$[ebp], -5          ; fffffffbH
                                       
                                      ; 15   :         printf( "%d", a );
                                       
                                          push    -5                  ; fffffffbH
                                          push    OFFSET FLAT:??_C@_02DPKJAMEF@?$CFd?$AA@
                                          call    _printf
                                       
                                      ; 16   :         scanf( "%d", &a );
                                       
                                          lea eax, DWORD PTR _a$[ebp]
                                          push    eax
                                          push    OFFSET FLAT:??_C@_02DPKJAMEF@?$CFd?$AA@
                                          call    _scanf
                                          add esp, 16                 ; 00000010H
                                          jmp SHORT $L58693
                                      $L58683:
                                       
                                      ; 17   :     }
                                      ; 18   :     __except(EXCEPTION_EXECUTE_HANDLER)
                                       
                                          [COLOR=red]mov  eax, 1
                                      $L58685:
                                          ret 0
                                      $L58684:
                                          mov esp, DWORD PTR __$SEHRec$[ebp][/COLOR]
                                      ; 19   :     {
                                      ; 20   :         printf( "should not be here. Maybe zero division?" );
                                       
                                          push    OFFSET FLAT:??_C@_0CJ@LGAHIOIG@should?5not?5be?5here?4?5Maybe?5zero?5d@
                                          call    _printf
                                          add esp, 4
                                      $L58693:
                                          mov DWORD PTR __$SEHRec$[ebp+20], -1
                                       
                                      ; 21   :     }
                                      ; 22   :     return 0;
                                       
                                          xor eax, eax
                                       
                                      ; 23   : }
                                       
                                      [COLOR=red] mov ecx, DWORD PTR __$SEHRec$[ebp+8]
                                          mov DWORD PTR fs:__except_list, ecx
                                          pop edi
                                          pop esi
                                          pop ebx
                                          mov esp, ebp
                                          pop ebp[/COLOR] ret 0
                                      _main   ENDP
                                      _TEXT   ENDS
                                      END


                                    Бросаются в глаза две вещи:
                                    1) большие накладные расходы на начало\завершение функции, где используются исключения
                                    2) то, что оптимизация при использовании SEH, если и не отключается, то сильно сдаёт.

                                    2-ое мне откровенно непонятно, в то время как первое заставило иначе взглянуть на своё использовании исключений.

                                    -юсртыхэю
                                    Цитата amk @
                                    Раскрутка стека программы операционной системой затруднена хотя бы потому, что программа может использовать какую-то свой, не определённый в системе метод хранения необходимой информации. А так и получится, если программа строится компилятором/сборщиком сторонних фирм, а не создателя ОС. В случае с Windows это особенно актуально, так как MS известна своим пристрастием включать в свои ОС недокументированные возможности.

                                    Но многие используют VisualStudio, который вполне от производителя ОС. А Borland тоже получил какое-то тайное знания от Microsoft касательно того, как реализовать обработку исключений ( по крайней мере, Matt Pietrek так считал ). Что же до Intel-овского компилятора, то у них замечательная дружба с Microsoft и они лучше многих знают внутренние структуры ( посмотреть хотя бы на VTune ). А какие ещё компиляторы популярны под Windows, чтобы считать эту проблему актуальной?
                                      Продолжаем эксперемент:
                                      VC 7.1 Код без исключений
                                      ExpandedWrap disabled
                                        void main()
                                        {
                                        00401000  push        ecx  
                                        00401001  push        esi  
                                            //PerformanceTest();
                                            int a = 10;
                                         
                                                a = 15;
                                                a += 20;
                                                a -= 40;
                                                printf( "%d", a );
                                        00401002  mov         esi,dword ptr [__imp__printf (402064h)]
                                        00401008  push        0FFFFFFFBh
                                        0040100A  push        offset string "%d" (4020D8h)
                                        0040100F  mov         dword ptr [esp+0Ch],0FFFFFFFBh
                                        00401017  call        esi  
                                                scanf( "%d", &a );
                                        00401019  lea         eax,[esp+0Ch]
                                        0040101D  push        eax  
                                        0040101E  push        offset string "%d" (4020D8h)
                                        00401023  call        dword ptr [__imp__scanf (402068h)]
                                         
                                                if (a > 0)
                                        00401029  mov         eax,dword ptr [esp+14h]
                                        0040102D  add         esp,10h
                                        00401030  test        eax,eax
                                        00401032  jle         main+3Eh (40103Eh)
                                                printf( "should not be here. Maybe zero division?" );
                                        00401034  push        offset string "should not be here. Maybe zero d"... (4020ACh)
                                        00401039  call        esi  
                                        0040103B  add         esp,4
                                         
                                            return;
                                        }
                                        0040103E  xor         eax,eax
                                        00401040  pop         esi  
                                        00401041  pop         ecx  
                                        00401042  ret

                                      Он же, но с С++-исключениями
                                      ExpandedWrap disabled
                                        void main()
                                        {
                                        00401000  push        ecx  
                                            //PerformanceTest();
                                            int a = 10;
                                         
                                            try
                                            {
                                                a = 15;
                                                a += 20;
                                                a -= 40;
                                                printf( "%d", a );
                                        00401001  push        0FFFFFFFBh
                                        00401003  push        offset string "%d" (4020ACh)
                                        00401008  mov         dword ptr [esp+8],0FFFFFFFBh
                                        00401010  call        dword ptr [__imp__printf (402064h)]
                                                scanf( "%d", &a );
                                        00401016  lea         eax,[esp+8]
                                        0040101A  push        eax  
                                        0040101B  push        offset string "%d" (4020ACh)
                                        00401020  call        dword ptr [__imp__scanf (402068h)]
                                            }
                                            catch (...)
                                            {
                                                printf( "should not be here. Maybe zero division?" );
                                            }
                                         
                                            return;
                                        }
                                        00401026  xor         eax,eax
                                        00401028  add         esp,14h
                                        0040102B  ret

                                      Он же, но с SEH
                                      ExpandedWrap disabled
                                        void main()
                                        {
                                        00401000  push        ebp  
                                        00401001  mov         ebp,esp
                                        00401003  push        0FFFFFFFFh
                                        00401005  push        4020E0h
                                        0040100A  push        offset _except_handler3 (40114Eh)
                                        0040100F  mov         eax,dword ptr fs:[00000000h]
                                        00401015  push        eax  
                                        00401016  mov         dword ptr fs:[0],esp
                                        0040101D  sub         esp,0Ch
                                        00401020  push        ebx  
                                        00401021  push        esi  
                                        00401022  push        edi  
                                        00401023  mov         dword ptr [ebp-18h],esp
                                            //PerformanceTest();
                                            int a = 10;
                                        00401026  mov         dword ptr [a],0Ah
                                         
                                            __try
                                        0040102D  mov         dword ptr [ebp-4],0
                                            {
                                                a = 15;
                                        00401034  mov         dword ptr [a],0Fh
                                                a += 20;
                                        0040103B  mov         dword ptr [a],23h
                                                a -= 40;
                                        00401042  mov         dword ptr [a],0FFFFFFFBh
                                                printf( "%d", a );
                                        00401049  push        0FFFFFFFBh
                                        0040104B  push        offset string "%d" (4020D8h)
                                        00401050  call        dword ptr [__imp__printf (402064h)]
                                                scanf( "%d", &a );
                                        00401056  lea         eax,[a]
                                        00401059  push        eax  
                                        0040105A  push        offset string "%d" (4020D8h)
                                        0040105F  call        dword ptr [__imp__scanf (402068h)]
                                        00401065  add         esp,10h
                                        00401068  jmp         $L39474+11h (401081h)
                                            }
                                            __except(EXCEPTION_EXECUTE_HANDLER)
                                        0040106A  mov         eax,1
                                        $L39481:
                                        0040106F  ret              
                                        $L39474:
                                        00401070  mov         esp,dword ptr [ebp-18h]
                                            {
                                                printf( "should not be here. Maybe zero division?" );
                                        00401073  push        offset string "should not be here. Maybe zero d"... (4020ACh)
                                        00401078  call        dword ptr [__imp__printf (402064h)]
                                        0040107E  add         esp,4
                                        00401081  mov         dword ptr [ebp-4],0FFFFFFFFh
                                            }
                                         
                                            return;
                                        }
                                        00401088  xor         eax,eax
                                        0040108A  mov         ecx,dword ptr [ebp-10h]
                                        0040108D  mov         dword ptr fs:[0],ecx
                                        00401094  pop         edi  
                                        00401095  pop         esi  
                                        00401096  pop         ebx  
                                        00401097  mov         esp,ebp
                                        00401099  pop         ebp  
                                        0040109A  ret


                                      Что называется, почувствуйте разницу...

                                      Добавлено
                                      В связи с чем предлагаю следующее дополнение к правилам раздела:
                                      Цитата

                                      Если кто-то берется утвержать, что та или иная языковая конструкция неэффективна, неоптимальна, просаживает производительность кода, и т. д. и т. п., то любое такое утверждение должно быть подкреплено не только кодом на С++, но и ассемблерным листингом (полученным по приведенному коду), иллюстрирующим утверждение, замерами производительности или любыми другими весомыми доказательствами. Иначе имеет смысл сразу же закрывать тему за недоказанностью "обвинений".
                                        Flex Ferrum

                                        Дополнение к правилам шикарное, за одним НО.
                                        Есть знание теоретическое и знание практическое. Может конкретно на этом примере так случилось, что результаты оказались такими неэффективными. А вдруг например на kernel-space или на другом компиляторе картина будет прямо противоположная. Если когда-нибудь занимался попыткамиотносительно точно замерить производительность, то поймёшь... Когда два теста без перекомпиляции но при перезагрузке ОС давали диаметрально разные результаты...
                                          Цитата TrefptYc @
                                          Дополнение к правилам шикарное, за одним НО.
                                          Есть знание теоретическое и знание практическое.

                                          Так потому и предлагается спорить не голословно, а с подобающей аргументацией. Кстати, если кто-то соберется выкинуть исключение, то код main начинает выглядеть так:
                                          ExpandedWrap disabled
                                            void main()
                                            {
                                            00401020  push        ebp  
                                            00401021  mov         ebp,esp
                                            00401023  push        0FFFFFFFFh
                                            00401025  push        offset __ehhandler$_main (401580h)
                                            0040102A  mov         eax,dword ptr fs:[00000000h]
                                            00401030  push        eax  
                                            00401031  mov         dword ptr fs:[0],esp
                                            00401038  sub         esp,8
                                            0040103B  push        ebx  
                                            0040103C  push        esi  
                                            0040103D  push        edi  
                                            0040103E  mov         dword ptr [ebp-10h],esp
                                                //PerformanceTest();
                                                int a = 10;
                                             
                                                try
                                                {
                                                    a = 15;
                                                    a += 20;
                                                    a -= 40;
                                                    printf( "%d", a );
                                            00401041  push        0FFFFFFFBh
                                            00401043  push        offset string "%d" (4020E8h)
                                            00401048  mov         dword ptr [ebp-4],0
                                            0040104F  mov         dword ptr [a],0FFFFFFFBh
                                            00401056  call        dword ptr [__imp__printf (40206Ch)]
                                                    scanf( "%d", &a );
                                            0040105C  lea         eax,[a]
                                            0040105F  push        eax  
                                            00401060  push        offset string "%d" (4020E8h)
                                            00401065  call        dword ptr [__imp__scanf (402070h)]
                                            0040106B  add         esp,10h
                                                    a /= foo___();
                                            0040106E  jmp         foo___ (401000h)
                                                    printf( "%d", a );
                                                }
                                                catch (...)
                                                {
                                                    printf( "should not be here. Maybe zero division?" );
                                            00401073  push        offset string "should not be here. Maybe zero d"... (4020BCh)
                                            00401078  call        dword ptr [__imp__printf (40206Ch)]
                                            0040107E  add         esp,4
                                                }
                                            00401081  mov         eax,offset $L37751 (401087h)
                                            00401086  ret              
                                             
                                                return;
                                            }
                                            00401087  mov         ecx,dword ptr [ebp-0Ch]
                                            0040108A  pop         edi  
                                            0040108B  pop         esi  
                                            0040108C  xor         eax,eax
                                            0040108E  mov         dword ptr fs:[0],ecx
                                            00401095  pop         ebx  
                                            00401096  mov         esp,ebp
                                            00401098  pop         ebp  
                                            00401099  ret
                                            Flex Ferrum

                                            Ну всё правильно. В твоём первом примере с С++-исключениями по ветке catch(...) пойти не могли, ведь, насколько я помню, С++ обработчтик не перехватывает железные исключения, а софтверных ты не кидал и деления на константук у тебя не было. поэтому компилятор просто убрал обработку исключений, как если бы он убрал конструкцию if(0){}. Так что адекватное практическое знание ещё получить нужно...
                                              Из этого, кстати, следует весьма интересный вывод. Пустой спецификатор исключений - вполне хороший способ избежать оверхеда. Т. е. если нетривиальный метод гарантирует, что не выкинет исключений (гарантия отсутствия ошибок), то имеет смысл помечать его как throw(), что позволит компилятору опимизировать его вызов.

                                              Добавлено
                                              Вот еще два примера кода. В обоих случаях вызывается метод foo___. Но в первом случае он может кидать любые исключения, а во втором случае помечен как throw().
                                              ExpandedWrap disabled
                                                void main()
                                                {
                                                push        ebp  
                                                mov         ebp,esp
                                                push        0FFFFFFFFh
                                                push        offset __ehhandler$_main (4015A0h)
                                                mov         eax,dword ptr fs:[00000000h]
                                                push        eax  
                                                mov         dword ptr fs:[0],esp
                                                sub         esp,8
                                                push        ebx  
                                                push        esi  
                                                    //PerformanceTest();
                                                    int a = 10;
                                                 
                                                    try
                                                    {
                                                        a = 15;
                                                        a += 20;
                                                        a -= 40;
                                                        printf( "%d", a );
                                                mov         esi,dword ptr [__imp__printf (40206Ch)]
                                                push        edi  
                                                mov         dword ptr [ebp-10h],esp
                                                push        0FFFFFFFBh
                                                push        offset string "%d" (4020E8h)
                                                mov         dword ptr [ebp-4],0
                                                mov         dword ptr [a],0FFFFFFFBh
                                                call        esi  
                                                        scanf( "%d", &a );
                                                lea         eax,[a]
                                                push        eax  
                                                push        offset string "%d" (4020E8h)
                                                call        dword ptr [__imp__scanf (402070h)]
                                                add         esp,10h
                                                        a /= foo___();
                                                call        foo___ (401000h)
                                                mov         ecx,eax
                                                mov         eax,dword ptr [a]
                                                cdq              
                                                idiv        eax,ecx
                                                        printf( "%d", a );
                                                push        eax  
                                                push        offset string "%d" (4020E8h)
                                                mov         dword ptr [a],eax
                                                call        esi  
                                                add         esp,8
                                                 
                                                    return;
                                                }
                                                mov         ecx,dword ptr [ebp-0Ch]
                                                pop         edi  
                                                pop         esi  
                                                xor         eax,eax
                                                mov         dword ptr fs:[0],ecx
                                                pop         ebx  
                                                mov         esp,ebp
                                                pop         ebp  
                                                ret              
                                                    }
                                                    catch (...)
                                                    {
                                                        printf( "should not be here. Maybe zero division?" );
                                                push        offset string "should not be here. Maybe zero d"... (4020BCh)
                                                call        dword ptr [__imp__printf (40206Ch)]
                                                add         esp,4
                                                    }
                                                mov         eax,offset $L37743 (40108Bh)
                                                ret


                                              ExpandedWrap disabled
                                                void main()
                                                {
                                                push        ecx  
                                                push        esi  
                                                    //PerformanceTest();
                                                    int a = 10;
                                                 
                                                    try
                                                    {
                                                        a = 15;
                                                        a += 20;
                                                        a -= 40;
                                                        printf( "%d", a );
                                                mov         esi,dword ptr [__imp__printf (40206Ch)]
                                                push        0FFFFFFFBh
                                                push        offset string "%d" (4020BCh)
                                                mov         dword ptr [esp+0Ch],0FFFFFFFBh
                                                call        esi  
                                                        scanf( "%d", &a );
                                                lea         eax,[esp+0Ch]
                                                push        eax  
                                                push        offset string "%d" (4020BCh)
                                                call        dword ptr [__imp__scanf (402070h)]
                                                        a /= foo___();
                                                call        foo___ (401000h)
                                                mov         ecx,eax
                                                mov         eax,dword ptr [esp+14h]
                                                cdq              
                                                idiv        eax,ecx
                                                        printf( "%d", a );
                                                push        eax  
                                                push        offset string "%d" (4020BCh)
                                                mov         dword ptr [esp+1Ch],eax
                                                call        esi  
                                                add         esp,18h
                                                    }
                                                    catch (...)
                                                    {
                                                        printf( "should not be here. Maybe zero division?" );
                                                    }
                                                 
                                                    return;
                                                }
                                                xor         eax,eax
                                                pop         esi  
                                                pop         ecx  
                                                ret
                                                Цитата Flex Ferrum @
                                                Он же, но с С++-исключениями
                                                Судя по листингу, никакой обработки нет - компилятор выкинул.

                                                Да и с POD-типами не совсем честно. Надо внутрь try засунуть какой-нибудь не-POD тип, например, vector. :)

                                                Добавлено
                                                меня опередили :)
                                                1 пользователей читают эту тему (1 гостей и 0 скрытых пользователей)
                                                0 пользователей:


                                                Рейтинг@Mail.ru
                                                [ Script execution time: 0,0706 ]   [ 15 queries used ]   [ Generated: 18.07.25, 03:04 GMT ]