На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
Модераторы: Qraizer, Hsilgos
Страницы: (6) 1 [2] 3 4 ... Последняя » все  ( Перейти к последнему сообщению )  
> "обработка исключений" vs "обработка кодов возврата"
    Чего? :blink:

    Добавлено
    <stacktrace>
      Цитата Qraizer @
      Чего?

      Я там редактировал, пока ты там читал! =) Перечитай есчо раз =)
        Я правильно прочитал. Ты предлагаешь мне схавать аппаратное исключение? Это оффтоп темы
          Цитата Qraizer @
          Я правильно прочитал. Ты предлагаешь мне схавать аппаратное исключение? Это оффтоп темы

          А ты что, в сказку попал?!!

          1) Есть сетевые ошибки, масса
          2) Есть ошибки устройств I/O, часто
          3) Крайний случай - тупо ошибки RAM, нечасто но видели

          Я тебе предлагаю это схавать! =)
            Majestio, не рекомендую троллить или подменять термины. Можешь, конечно, подумать на предмет
            ExpandedWrap disabled
              LONG WINAPI translateException(EXCEPTION_POINTERS *excPtr)
              {
                const unsigned EH_EXCEPTION_NUMBER = ('msc' | 0xE0000000);    // <- undocumented
               
                if (excPtr->ExceptionRecord->ExceptionCode == EH_EXCEPTION_NUMBER)
                  return EXCEPTION_CONTINUE_SEARCH;
                throw StackTrace(excPtr->ExceptionRecord->ExceptionCode);     // dangerously
              }
               
              // нуль
              int b = 0;
               
              int g()
              {
                return 123 / b;       // деление на нуль
              }
               
              int f()
              {
                return g();
              }
               
              int main()
              {
                HANDLE hExc = AddVectoredExceptionHandler(1, translateException);
               
                if (hExc == NULL)
                  return std::cout << "AddVectoredExceptionHandler() fails: " << GetLastError() << std::endl,
                         1;
               
                Guard excRem([=](){ RemoveVectoredExceptionHandler(hExc); });
               
                try
                {
                  f();
                }
                catch(const StackTrace& exc)
                {
                  std::clog << std::hex << exc.why() << "\nStack trace -->:\n" << exc.getStack();
                  return 2;
                }
                return 0;
              }
            но это не имеет никакого отношения ни к
            Цитата Majestio @
            1) Есть сетевые ошибки, масса
            2) Есть ошибки устройств I/O, часто
            3) Крайний случай - тупо ошибки RAM, нечасто но видели
            ни к теме C++EH
              Цитата Qraizer @
              Majestio, не рекомендую троллить или подменять термины.

              И в помыслах не было! Просто я немножко на позитиве в следствие принятия соответствующих, скажем так, пищевых добавок :drinks:

              Цитата Qraizer @
              Ты предлагаешь мне схавать аппаратное исключение?

              Желаю уточнить. Мы сейчас говорим о юзер-спэйсе. И все что может быть "выкинуто" аппаратурой - мы не ловим напрямую, а ждем реакции исключительно операционной системы. Работу проги в режиме ядра операционной системы, или тем паче, вообще без операционной системы - мы щяс не рассматриваем. Поэтому да - сетевые ошибки, и ошибки I/O могут уверенно прилетать в юзерспейс, уже тёплые, ламповые, готовые. И там (в юзерспейсе) они могут и должны обрабатываться. Что касается аппаратных ошибок RAM - тут согласен. Эту "беду" на прикладном уровне очень сложно, а чаще и невозможно, победить.

              Цитата Qraizer @
              WINAPI

              А вот тут ты очень обидно сказал!!! :'( Тем самым проигнорировал линуксоидов, бисидишников и большое количество mac-пролетариев!

              И кстати тут:
              Цитата Qraizer @
              int g()
              {
                return 123 / b;       // деление на нуль
              }

              В рамках программирования "здорового человека" нужно немного поправить сигнатуру функции. А именно проверять b на нуль. И принимать одно из решений, учитывая тему топика: 1) Выкидывать свое исключение, оставив сигнатуру функции как есть 2) Либо поступить как поступают в других ЯП типа Rust/Dart - возвращать не int, а Result. Который, для упрощения, есть структура с полями "валидное_значение?" и "значение". Ну если не структура, пусть будет std::tuple. Не важно, главное принцип - "видишь деление, проверь". Тоже самое касается и остальных мест, где могут быть проблемсы.
                Ты всё-таки определись, что ты хочешь. О ловле контекста, приводящему к аппаратному отказу, с целью его недопущения я уже писал:
                ExpandedWrap disabled
                  std::optional<int> g()
                  {
                    return b == 0 ? decltype(g())() : 123 / b;       // деление на нуль
                  }
                   
                  int f()
                  {
                    return g().value();
                  }
                g() учитывает возможный сбой, f() не учитывает и бросит std::bad_optional_access. Или:
                ExpandedWrap disabled
                  std::variant<int, std::error_code> g()
                  {
                    using retType = decltype(g());
                    return b == 0 ? retType(std::make_error_code(std::errc::invalid_argument)) : retType(123 / b);       // деление на нуль
                  }
                   
                  int f()
                  {
                    return std::get<int>(g());
                  }
                Бросит std::bad_variant_access. Но вопрос остаётся: ты от меня хотел, чтобы я просто повторил ранее сказанное?
                Если же мы говорим от аппаратных отказах, то Стандартного способа преобразовать исключения низкого уровня в C++EH не существует и вряд ли когда-нибудь будет существовать. В WINAPI испокон веков существовал SEH (даже в Win16, хоть и в очень зачаточном виде). Это часть API, и это позволяет работать с ними единообразным образом на любых уровнях. Даже в ядре. (Даже C++EH в ядре.) Однако WINAPI поддерживает не только C++, поэтому возлагать на ОС прям вот C++EH шоколадно. Однако несложно реализовать трансляцию SEH в C++EH. Выше корявый, но пример. Что до ваших никсов, то это ваши сложности. У вас есть сигналы, вот с ними и ...думайте. Мне влом, не хватало ещё какой-нить в STM32 под realtime tiny os переносить его десяток исключений с парой десятков их источников.
                  Цитата Qraizer @
                  Ты всё-таки определись, что ты хочешь.

                  А я уже определился! Только одно прошу - давай ты без нервов, давай без них самих! =)

                  В процессе обсуждения вопроса мы выявили два "важных" момента:

                  1) Обеспечение транзакционной целостности объектов - тут понятно и просто
                  2) Выброс стека вызовов при ловле исключений - тут (лично для меня пока не просто)

                  Я все "почитаю и изучу". Ток одна просьба. Qraizer, не поднимай ни себе и не остальным нервы. Мы тут все более-менее на равных. Кто-то более компетентен, кто менее. Но в этом суть и соль общения. Очень тебя прошу, ты же профи. Держи себя в рамках, даже если к тебе обращаются специалисты гораздо низшего относительно тебя уровня!

                  Добавлено
                  Qraizer, да, кстати, да ... "Деление на нуль" - наверное одно, и наверное, единственное исключение, которое можно обозвать "аппаратным". Или не? Какие еще подобные исключения можно словить в "юзер-спейсе", которые не обрабатывала операционная система, а просто "вбросила"? И это не просто стёб, и не censored. Тут дело разработок. Просто скажи - вот они (список), или скажи "я погорячился". Прощу меня понять - мне важна суть, а не прав ты или не прав. Вообще на второе забей! Я триста раз могу ошибаться, но я тут чтобы получать достоверную инфу. Без обид!
                  Сообщение отредактировано: Qraizer -
                    #AC и #BOUND (последнее давно не используется)
                      В плане дизайна обработки ошибок я бы сейчас рекомендовал использовать std::optional (иногда std::variant) и новенький std::expected.
                      Ну и именно исключения оставить на тот случай, когда совсем никак без них не обойтись (см. первое сообщение Qraizerа)

                      А самое главное не забывать про т.н. гарантии безопасности исключений, введенные Саттером (или возможно Абрахамсом, но лично я впервые прочел у Саттера).
                      Ну базовая, строгая и гарантия отсутствия исключений. Это достаточно легко гуглится, не вижу смысла тут писать подробности.
                      Без понимания этих принципов будет очень сложно (невозможно?) написать качественный код с использованием исключений.
                      Сообщение отредактировано: D_KEY -
                        Цитата D_KEY @
                        Без понимания этих принципов будет очень сложно (невозможно?) написать качественный код с использованием исключений.
                        Бери выше. Без этих принципов писать надёжный код вообще вряд ли получится, и без разницы, исключения или нет и на каком языке пишешь.
                          Majestio, если заглянуть в winnt.h, то там их вагон и маленькая тележка, штук 60. Не все они аппаратные, но все низкоуровневые. Типа STATUS_GUARD_PAGE_VIOLATION, STATUS_BREAKPOINT, STATUS_STACK_OVERFLOW итп. Конкретно аппаратных немного:
                          Код исключенияПричина исключения
                          STATUS_ACCESS_VIOLATIONЧтение или запись в недоступный адрес в памяти.
                          STATUS_BREAKPOINTОбнаружение аппаратной точки останова; используется только в отладчиках.
                          STATUS_DATATYPE_MISALIGNMENTЧтение и запись в данные по адресу с неверным выравниванием. Например, 16-разрядные записи должны выравниваться относительно машинных слов с границей 2 байта. (Неприменимо к процессорам Intel 80x86.)
                          STATUS_FLOAT_DIVIDE_BY_ZEROДеление значения с плавающей запятой на 0,0.
                          STATUS_FLOAT_OVERFLOWПревышение максимальной положительной экспоненты с плавающей запятой.
                          STATUS_FLOAT_UNDERFLOWПревышение модуля наименьшей отрицательной экспоненты с плавающей запятой.
                          STATUS_FLOATING_RESEVERED_OPERANDИспользование зарезервированного формата с плавающей запятой (недопустимое использование формата).
                          STATUS_ILLEGAL_INSTRUCTIONПопытка выполнить код инструкции, не определенной процессором.
                          STATUS_PRIVILEGED_INSTRUCTIONВыполнение инструкции, которая не разрешена в текущем режиме машины.
                          STATUS_INTEGER_DIVIDE_BY_ZEROДеление значения целочисленного типа на 0.
                          STATUS_INTEGER_OVERFLOWПопытка выполнения операции, которая превышает диапазон целочисленного типа.
                          STATUS_SINGLE_STEPВыполнение одной инструкции в пошаговом режиме; используется только в отладчиках.
                          Но тут встаёт вопрос: а можно ли их считать отдельно от вон того списка из 60 элементов?
                            P.S. У x86/64 исключений больше.
                            Table 5-1. Protected-Mode Exceptions and Interrupts
                            Vector No.Mne-monicDescriptionTypeError CodeSource
                            0#DEDivide ErrorFaultNoDIV and IDIV instructions.
                            1#DBRESERVEDFault/ TrapNoFor Intel use only.
                            2NMI InterruptInterruptNoNonmaskable external interrupt.
                            3#BPBreakpointTrapNoINT 3 instruction.
                            4#OFOverflowTrapNoINTO instruction.
                            5#BRBOUND Range ExceededFaultNoBOUND instruction.
                            6#UDInvalid Opcode (Undefined Opcode)FaultNoUD2 instruction or reserved opcode.1)
                            7#NMDevice Not Available (No Math Coprocessor)FaultNoFloating-point or WAIT/FWAIT instruction.
                            8#DFDouble FaultAbortYes (zero)Any instruction that can generate an exception, an NMI, or an INTR.
                            9Coprocessor Segment Overrun (reserved)FaultNoFloating-point instruction.2)
                            10#TSInvalid TSSFaultYesTask switch or TSS access.
                            11#NPSegment Not PresentFaultYesLoading segment registers or accessing system segments.
                            12#SSStack-Segment FaultFaultYesStack operations and SS register loads.
                            13#GPGeneral ProtectionFaultYesAny memory reference and other protection checks.
                            14#PFPage FaultFaultYesAny memory reference.
                            15(Intel reserved. Do not use.)No
                            16#MFx87 FPU Floating-Point Error (Math Fault)FaultNox87 FPU floating-point or WAIT/FWAIT instruction.
                            17#ACAlignment CheckFaultYes (Zero)Any data reference in memory.3)
                            18#MCMachine CheckAbortNoError codes (if any) and source are model dependent.4)
                            19#XMSIMD Floating-Point ExceptionFaultNoSSE/SSE2/SSE3 floating-point instructions5)
                            20-31Intel reserved. Do not use.
                            Как к ним относится WINAPI, беспонятия, не интересовался.

                            1) The UD2 instruction was introduced in the Pentium Pro processor.
                            2) Processors after the Intel386 processor do not generate this exception.
                            3) This exception was introduced in the Intel486 processor.
                            4) This exception was introduced in the Pentium processor and enhanced in the P6 family processors.
                            5) This exception was introduced in the Pentium III processor.
                              Цитата Qraizer @
                              STATUS_FLOAT_DIVIDE_BY_ZERO Деление значения с плавающей запятой на 0,0.
                              STATUS_FLOAT_OVERFLOW Превышение максимальной положительной экспоненты с плавающей запятой.
                              STATUS_FLOAT_UNDERFLOW Превышение модуля наименьшей отрицательной экспоненты с плавающей запятой.
                              STATUS_FLOATING_RESEVERED_OPERAND Использование зарезервированного формата с плавающей запятой (недопустимое использование формата).

                              Вот эти 4 это просто флаги в fpu.StatusWord и как реальные Exception они не генерируются. Т.е. они софтверные и выбрасываются после проверки флага в регистре после fpu инструкции.
                                Цитата Qraizer @
                                Majestio, если заглянуть в winnt.h, то там их вагон и маленькая тележка, штук 60. Не все они аппаратные, но все низкоуровневые. Типа STATUS_GUARD_PAGE_VIOLATION, STATUS_BREAKPOINT, STATUS_STACK_OVERFLOW итп. Конкретно аппаратных немного:

                                :wacko:

                                Ну, положим, проверку деления на нуль можно делать, и нужно ... Но где и как делать проверку остального, к примеру STATUS_ILLEGAL_INSTRUCTION. Я даже не знаю - смогу ли я такое сгенерировать специально! Ну может быть какими-то ассемблерными вставками ... и то, не уверен.
                                1 пользователей читают эту тему (1 гостей и 0 скрытых пользователей)
                                0 пользователей:


                                Рейтинг@Mail.ru
                                [ Script execution time: 0,0418 ]   [ 15 queries used ]   [ Generated: 15.06.25, 22:11 GMT ]