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

    На С++ еще интринсики есть. Можно инструкции генерировать без asm вставок. А вот некоторые либы могут быть откомпилированы с использованием либо sse4+ либо на avx/avx256/avx512/avx10.2 (последнее в ближайшем будущем). И вот тут у проца может начаться несварение этих инструкций. Для sse4+ нужен минимум i5 (на i3 или pentium их нет), а для avx256 уже минимум i7. Но это только по линейке интелов. У амд свои приколы с этим с есть свои специфические инструкции.
      Цитата macomics @
      Вот эти 4 это просто флаги в fpu.StatusWord и как реальные Exception они не генерируются. Т.е. они софтверные и выбрасываются после проверки флага в регистре после fpu инструкции.
      Ты не учитываешь, что это WinAPI, а не конкретная процессорная архитектура. На MIPS, например, FLOAT OVERFLOW является вполне себе дефолтовым поведением после reset. К тому же не стоит забывать о всяких там _control87(), _controlfp() и __control87_2()
        Цитата D_KEY @
        В плане дизайна обработки ошибок я бы сейчас рекомендовал использовать std::optional (иногда std::variant) и новенький std::expected.
        Ну и именно исключения оставить на тот случай, когда совсем никак без них не обойтись (см. первое сообщение Qraizerа)

        Пасиба! Вот эта тема как-то пролетела мимо меня. Оставлю пока это тут чтобы потом почитать.
          Цитата Majestio @
          Цитата D_KEY @
          В плане дизайна обработки ошибок я бы сейчас рекомендовал использовать std::optional (иногда std::variant) и новенький std::expected.
          Ну и именно исключения оставить на тот случай, когда совсем никак без них не обойтись (см. первое сообщение Qraizerа)

          Пасиба! Вот эта тема как-то пролетела мимо меня. Оставлю пока это тут чтобы потом почитать.

          Статья про optional только вроде. Если есть возможность использовать новые стандарты и компиляторы, то советую не забыть и про std::expected :)
            Цитата Qraizer @
            На MIPS, например, FLOAT OVERFLOW является вполне себе дефолтовым поведением после reset.

            Не видел Windows для MIPS
              Зачем вы вообще говорите про WinAPI, мы вроде в "общих вопросах", кажется, тут обычно мы говорим про стандарт, а если переходить на ОС и архитектуры, то нужно как-то затрагивать как минимум несколько наиболее востребованных.
                D_KEY, ну кто ж виноват, что аппаратные исключения неСтандартизированы. Сам подумывал перенести, но контекст потеряется. Та и куда? Вот Majestio счас кинет не менее корявый пример на сигналах и что, опять переносить?

                Добавлено
                macomics, Win32 вышел под x86, Alpha, MIPS, PPC и какой-то VLIW, не помню какой. Постепенно набор платформ сокращался, т.к. они уходили с рынка, вытесняясь Intel и AMD. Последней ушла вроде бы Alpha, зато на какое-то время к ним добавился Itanium.
                Сообщение отредактировано: Qraizer -
                  Цитата Qraizer @
                  Win32 вышел под x86, Alpha, MIPS, PPC и какой-то VLIW, не помню какой.

                  Вот под PPC видел, но это когда было... 64-битных сейчас и нету под другие, кроме x86_64, но я может и не встречал.

                  Цитата Qraizer @
                  зато на какое-то время к ним добавился Itanium.

                  Это же тот же Intel (хотя и другая архитектура)
                  Сообщение отредактировано: macomics -
                    Цитата Qraizer @
                    D_KEY, ну кто ж виноват, что аппаратные исключения неСтандартизированы

                    А я так до конца и не понял, откуда тут взялась тема аппаратых исключений :)
                    Вроде вопрос об исключениях в C++ и вообще дизайне обработки ошибок.
                      А куда от них деться-то? Тема вечная. Я надеялся, что тут она не всплывёт, всё ж о Чистом С++ тут, но коль уж всплыла, а Стандартными методами о ней не поговорить, то либо так, либо раскидать тред по нескольким разделам и темам. Не думаю, что так было бы удобнее, пусть уж в одном месте будет.
                        Цитата Qraizer @
                        А куда от них деться-то? Тема вечная. Я надеялся, что тут она не всплывёт, всё ж о Чистом С++ тут, но коль уж всплыла, а Стандартными методами о ней не поговорить, то либо так, либо раскидать тред по нескольким разделам и темам. Не думаю, что так было бы удобнее, пусть уж в одном месте будет.

                        Qraizer, не, всё-таки ты какими-то неведомыми путями мой вопрос "прибил" к аппаратным исключениям. Ну да, с твоей подачи я попробовал этот ваш вендовый SEH, да работает:

                        ExpandedWrap disabled
                          #include <iostream>
                          #include <windows.h>
                           
                          void div_function() {
                           int d = 1;
                           d--;
                           int p = 10/d;
                          }
                           
                          int main() {
                            __try {
                              div_function();
                            }
                            __except (EXCEPTION_EXECUTE_HANDLER) {
                              std::cout << "There's been an exception!" << std::endl;
                              DWORD exceptionCode = GetExceptionCode();
                              switch (exceptionCode) {
                                case STATUS_ACCESS_VIOLATION:
                                    std::cout << "Memory access error!" << std::endl;
                                    break;
                                case STATUS_INTEGER_DIVIDE_BY_ZERO:
                                    std::cout << "Error: division by zero (integer)!" << std::endl;
                                    break;
                                case STATUS_FLOAT_DIVIDE_BY_ZERO:
                                    std::cout << "Error: division by zero (float)!" << std::endl;
                                    break;
                                default:
                                    std::cout << "Unknown error: " << exceptionCode << std::endl;
                                    break;
                              }
                            }
                            return 0;
                          }

                        Но на самом деле меня интерсовал только вот такой вопрос:

                        Цитата Majestio @
                        В рамках программирования "здорового человека" нужно немного поправить сигнатуру функции. А именно проверять b на нуль. И принимать одно из решений, учитывая тему топика: 1) Выкидывать свое исключение, оставив сигнатуру функции как есть 2) Либо поступить как поступают в других ЯП типа Rust/Dart - возвращать не int, а Result. Который, для упрощения, есть структура с полями "валидное_значение?" и "значение". Ну если не структура, пусть будет std::tuple. Не важно, главное принцип - "видишь деление, проверь". Тоже самое касается и остальных мест, где могут быть проблемсы.

                        После обсуждения у меня появилось три варианта:

                        ExpandedWrap disabled
                          #include <iostream>
                          #include <optional>
                          #include <stdexcept>
                           
                          bool safe_divide_1(int numerator, int denominator, double& result) noexcept {
                            if (denominator == 0) return false;
                            result = static_cast<double>(numerator) / denominator;
                            return true;
                          }
                           
                          std::optional<double> safe_divide_2(int numerator, int denominator) noexcept {
                            if (denominator == 0) return std::nullopt;
                            return static_cast<double>(numerator) / denominator;
                          }
                           
                          double safe_divide_3(int numerator, int denominator) {
                            if (denominator == 0) throw std::runtime_error("Division by zero!");
                            return static_cast<double>(numerator) / denominator;
                          }
                           
                          int main() {
                           
                            // первый вариант
                            double result1;
                            if (safe_divide_1(10, 0, result1)) {
                                std::cout << "Result 1: " << result1 << std::endl;
                            } else {
                                std::cout << "Error 1: Division by zero!" << std::endl;
                            }
                           
                            // второй вариант
                            auto result2 = safe_divide_2(10, 0);
                            if (result2) {
                                std::cout << "Result 2: " << *result2 << std::endl;
                            } else {
                                std::cout << "Error 2: Division by zero!" << std::endl;
                            }
                            
                            // третий вариант  
                            try {
                              double result3 = safe_divide_3(10, 0);
                              std::cout << "Result 3: " << result3 << std::endl;
                            } catch (const std::exception &e) {
                                std::cout << "Error 3: " << e.what() << std::endl;
                            }
                            
                            return 0;
                          }

                        Которые функционально выполняют всё тоже самое, я имею ввиду именно в этом коде. И по количеству строк, и примерно по количеству буквов, да и по читаемости - они все примерно равны. Хотелось бы какой-то синтетический пример, где обработка исключений делала бы код более компактным, чем использование кодов возврата, но не в ущерб читаемости.
                          Цитата Majestio @
                          Qraizer, не, всё-таки ты какими-то неведомыми путями мой вопрос "прибил" к аппаратным исключениям.
                          ...
                          Но на самом деле меня интерсовал только вот такой вопрос:

                          Цитата Majestio @
                          В рамках программирования "здорового человека" нужно немного поправить сигнатуру функции. А именно проверять b на нуль. И принимать одно из решений, учитывая тему топика: 1) Выкидывать свое исключение, оставив сигнатуру функции как есть 2) Либо поступить как поступают в других ЯП типа Rust/Dart - возвращать не int, а Result. Который, для упрощения, есть структура с полями "валидное_значение?" и "значение". Ну если не структура, пусть будет std::tuple. Не важно, главное принцип - "видишь деление, проверь". Тоже самое касается и остальных мест, где могут быть проблемсы.
                          Что ты имел в виду, это хорошее пояснение, но я отвечал на это:
                          Цитата Majestio @
                          Давай ты решишь (в рамках сабжа!!!) другую задачу:

                          1) Задается произвольная матрица целых чисел размерностью 3x3
                          2) Одно из чисел (пусть одно) получит значение "нуль".
                          3) Нужно получить матрицу-результат = каждое значение исходной матрицы деленное на минимальное значение чисел из матрицы (что явно не есть нуль, но быть может)

                          Нужно словить (это просто) когда очередной член матрицы делится на минимальное значение матрицы (равное нулю) - и самое главное, словить в расчетах первое деление на нуль. И вывести стек вызовов.
                          Разве я что-то сделал не так?

                          Добавлено
                          P.S. Последующее
                          Цитата Qraizer @
                          Я правильно прочитал. Ты предлагаешь мне схавать аппаратное исключение? Это оффтоп темы
                          явно показывает моё нежелание продолжать эту тему, но после
                          Цитата Majestio @
                          1) Есть сетевые ошибки, масса
                          2) Есть ошибки устройств I/O, часто
                          3) Крайний случай - тупо ошибки RAM, нечасто но видели

                          Я тебе предлагаю это схавать! =)
                          я вообще потерялся в твоих желаниях, ибо оно вообще никоим боком не относится к теме с матрицами.
                            Цитата Qraizer @
                            Разве я что-то сделал не так?

                            Ты перевел разговор на аппаратные исключения. Я кагбэ поддержал. Но ловить деление на нуль можно и обычной предварительной проверкой ... с последующей обработкой ... исключений или кодов возврата.

                            Цитата Qraizer @
                            я вообще потерялся в твоих желаниях, ибо оно вообще никоим боком не относится к теме с матрицами.

                            А вот и нет ;) Мне чуйка подсказывает, что бóльшую красоту обработка ошибок в виде выброса и последующей обработки исключений - покажет при использовании ООП, а не при обычном структурном программировании. В плане примера ООП, в виде темы матриц мне показался самым примитивным и понятным даже школьнику. Вот такой мой довод. Сорян если я был слишком неточен в выражении своих вопросов :lol:
                              Цитата Qraizer @
                              P.S. Я тем не менее с удовольствием посмотрел бы на транслятор сигналов POSIX в C++EH хотя бы краем глаза.

                              Ну можно замутить отдельную тему для общего участия. Но я бы принял участие только при одном условии - использование "Шаблонов проектирования банды четырех" и "Принципов СОЛИДА". Ибо просто "а давайте навелосипедим кроссплатформенную шляпу-обёртку на С++" меня как-то не вдохновляет. Причину для себя понимаю - прикладной надобности у меня щя нет по этой теме, соответственно как-то автоматически включается "тонкое искусство пофигизма". А с ним бороться не айс! :-?

                              Скрытый текст
                              Тонкое искусство пофигизма

                              Прикреплённая картинка
                              Прикреплённая картинка
                                Цитата Majestio @
                                Ну да, с твоей подачи я попробовал этот ваш вендовый SEH, да работает:

                                Можно ещё заменить ExceptionFilter.
                                Те перехватить/заменить мессэдж бокс типа
                                "..инструкция по адресу ... обратилась по адресу ... Память не может быть Read".
                                Для этого используется "::SetUnhandledExceptionFilter".
                                В результате можно получить всю необходимую диагностику.
                                Однако, в отличии от многочисленных блоков __try / __except
                                обнаружение места исключения будет дольше и сложнее.
                                1 пользователей читают эту тему (1 гостей и 0 скрытых пользователей)
                                0 пользователей:


                                Рейтинг@Mail.ru
                                [ Script execution time: 0,0844 ]   [ 17 queries used ]   [ Generated: 3.09.25, 10:04 GMT ]