Форум программистов, компьютерный форум, киберфорум
Наши страницы
С++ для начинающих
Войти
Регистрация
Восстановить пароль
 
 
Рейтинг 4.88/8: Рейтинг темы: голосов - 8, средняя оценка - 4.88
krazyd
16 / 0 / 2
Регистрация: 10.11.2012
Сообщений: 116
1

Способы обработки ошибочных ситуаций

02.08.2015, 22:31. Просмотров 1648. Ответов 28
Метки нет (Все метки)

Добрый вечер!!

Расскажите ваше мнение на тему обработки ошибок, как лучше реализовать?

Заранее благодарю вас за ответы!!
0
Лучшие ответы (1)
QA
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
02.08.2015, 22:31
Ответы с готовыми решениями:

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

Обработки исключительных ситуаций
Объясните, что от меня хотят, а то уже мозг кипит ... 7. Не абстрактный класс В является...

Какие способы самые удобные/рациональные способы регистрации ошибок есть?
Задался вопросом, а как регистрировать ошибки? При этом чтобы и выглядело это красиво, и понятно...

Добавить проверку на ввод ошибочных данных
Пожалуйста, помогите сделать так чтобы при вводе ошибочных данных выходил текст "vveli nekorrektnie...

Есть ли в SQL аналог обработки исключительных ситуаций?
Есть SQL аналог обработки исключительных ситуаций?

28
eledev
55 / 55 / 39
Регистрация: 19.03.2015
Сообщений: 167
02.08.2015, 22:48 2
с помощью исключений
1
krazyd
16 / 0 / 2
Регистрация: 10.11.2012
Сообщений: 116
02.08.2015, 22:50  [ТС] 3
А можно поподробнее) Или может книгу посоветуете?
0
eledev
55 / 55 / 39
Регистрация: 19.03.2015
Сообщений: 167
02.08.2015, 23:02 4
в случае обнаружения ошибки исключения позволяют прервать поток выполнения программы и передать упралвение обработчику ошибок.
исключения описаны в любом учебнике по C++. например Бьерн Страуструп - Язык программирования C++.
еще очень хорошая книга - Брюс Эккель, Чак Эллисон - Философия C++
1
02.08.2015, 23:02
Убежденный
Ушел с форума
Эксперт С++
16255 / 7321 / 1183
Регистрация: 02.05.2013
Сообщений: 11,637
Записей в блоге: 1
Завершенные тесты: 1
02.08.2015, 23:55 5
Лучший ответ Сообщение было отмечено Ilot как решение

Решение

Цитата Сообщение от krazyd Посмотреть сообщение
Расскажите ваше мнение на тему обработки ошибок, как лучше реализовать?
1) Обрабатывать все возможные ошибки. Все. Повторю еще раз - все. Да, все.
Многие почему-то этого не делают. Если некая функция может вернуть false, вы
обязаны проверить это. Если в программе вызывается три сотни разных функций,
каждая из которых может завершиться ошибкой, вы обязаны написать код проверки
возвращаемого значения к каждой из них. Если метод некоего класса может выбрасывать
исключение, вы не должны помещать код его вызова в try/catch с пустым блоком catch -
это худшее, что можно придумать. Если некая операция или последовательность операций
завершается неудачей, то самое плохое, что можно в этом случае сделать - тихо
замолчать факт ошибки или, что еще хуже, попытаться выполнить ту же операцию, но
каким-то другим способом.

Не следование этому простому, на первый взгляд, принципу, влечет за собой то, что
лично я называю "пробрасывание ошибки" или "распостранение ошибки". Вместо того, чтобы
быть пойманной и четко классифицированной сразу по месту возникновения, вместе с
кодами исключения, стек-трейсом и другой полезной информацией, ошибка маскируется и
плавает в программе где-то на дне еще некоторое время, после чего все равно всплывает,
но уже совершенно в другом месте и с гораздо более невнятными симптомами, когда
возможности для ее диагностики уже нет. Искать такие ошибки, как правило, уже бесполезно.

Суть качественной обработки ошибок - максимально резкая реакция на их возникновение,
вместе со сбором максимально полной информации о контексте. Разумеется, есть ошибки
логические, которые являются ожидаемыми, например, невозможность сохранить данные в файл
из-за отсутствия прав на запись. В этом случае, очевидно, следует показать пользователю
какое-то осмысленное, "человеческое" сообщение и продолжить работу адекватным и наиболее
ожидаемым для него способом. Все остальное, что попадает в класс "unexpected", "overflow",
"no memory", деление на ноль и т.п., должно обрабатываться соответствующим образом.

2) Принцип в пункте 1 распостраняется на ключевые аспекты архитектуры приложения.
Если есть некий API, он должен быть спроектирован так, чтобы его можно было использовать
лишь одним, и никаким другим способом. И при попытке хоть что-то сделать не так должна
возвращаться ошибка. Если некий клиентский код, работая с нашим протоколом обмена данными,
посылает их не в том порядке, не с теми заголовками, с неверной длиной и т.п., то ни в
коем случае не следует пытаться "угадать" намерения клиента. Снова лучшая стратегия здесь -
сразу прервать обработку и вернуть соответствующий код ошибки. Как привередливая и
чрезмерно внимательная к деталям тетка. Вообще, чем уже "коридор" выполнения кода, тем
меньше возможностей где-то накосячить и сойти пути, который был намечен разработчиком.
Это один из ключевых принципов.

3) Не следует пытаться "восстановиться" после какой-то критической ошибки. Самое лучшее и
простое - дать программе просто упасть, сообщив пользователю о том, что произошло, ну возможно
еще снять крэш-дамп и создать логи. Не следует применять здесь какие-то "умные" стратегии,
они все равно будут нелепы.

4) Слой обработки ошибок должен быть четко отделен от слоя бизнес-логики приложения.
Иначе вы рискуете получить спагетти-код, нашпигованный if-ами через каждые три строчки.
Такой код очень трудно понимать, т.к. "лес" не видно за "деревьями". Исключения обычно
помогают достичь этой цели, к тому же их, в отличие от true/false и кодов возврата,
нельзя проигнорировать. То есть, где-то на низком уровне мы пишем реализацию, со всеми
свойственными ей заморочками, детализацией, проверкой ошибок и т.п., а сверху должен
быть простой, очевидный, компактный и самодокументированный код, чтобы одного взгляда
на который для любого смертного, даже не знакомого с программированием, хватило бы
для понимания того, что этот код делает.

5) "Исключения vs коды возврата" - руководствуемся соображениями пункта 4 (исключения
позволяют этого достигнуть), а также тем, что в объект исключения можно запихнуть любое
количество полезной информации. Но при этом учитываем перфоманс (коды быстрее) и вопросы
переносимости (выброс исключения даже за пределы модуля уже может привести к проблемам, а
из-за отсутствия ABI они не совместимы между компиляторами и, иногда, между разными
версиями одного и того же компилятора).

6) Ассерты, проверки инвариантов и тому подобное, должны быть расставлены на каждом шагу.
Это помогает отслеживать возникновение ошибок при внесении изменений в код, что очень важно.
Хороший ассерт, который вдруг выстрелил, сразу дает понять, что именно произошло и почему.
12
jupman
230 / 133 / 19
Регистрация: 10.11.2015
Сообщений: 305
10.07.2016, 08:12 6
Цитата Сообщение от Убежденный Посмотреть сообщение
То есть, где-то на низком уровне мы пишем реализацию, со всеми
свойственными ей заморочками, детализацией, проверкой ошибок и т.п., а сверху должен
быть простой, очевидный, компактный и самодокументированный код, чтобы одного взгляда
на который для любого смертного, даже не знакомого с программированием, хватило бы
для понимания того, что этот код делает.
Убежденный, привет. Вот смотрите, допустим обернули мы код (на низком уровне, в функции main например) в блок try. К примеру в этом коде есть несколько вызовов new. Как мы узнаем какой из вызовов сфэйлил? Из-за данной проблемы приходится писать спагетти-код:
C++
1
2
3
4
5
6
7
8
9
    try {
 
        pMem = new int[szMem]; 
    }
    catch (bad_alloc) {
 
        // здесь вывод номера строки, имени функции etc, т.о. будем знать конкретное место
        // далее бросаем свое исключение чтобы попасть в блок catch в функции main
    }
Как быть?
0
Убежденный
Ушел с форума
Эксперт С++
16255 / 7321 / 1183
Регистрация: 02.05.2013
Сообщений: 11,637
Записей в блоге: 1
Завершенные тесты: 1
10.07.2016, 08:27 7
Можно заменить new на какую-нибудь функцию/макрос, которая будет делать
try/catch и формировать всю нужную информацию в случае возникновения исключения.

А можно вообще не перехватывать bad_alloc. Все-таки это критическая ситуация, в
которой вряд ли получится что-то сделать. Пускай программа сразу падает.
Далее система создаст крэш-дамп и по нему уже можно будет разбираться - то ли
памяти в системе не хватило, то ли упало как итог утечки, которую надо чинить.
1
mporro
306 / 101 / 18
Регистрация: 04.07.2014
Сообщений: 571
10.07.2016, 12:55 8
Ошибки бывают разные.
И я всё больше склоняюсь к тому, чтобы использовать исключения только для обрушения программы.
Во всех остальных случаях, когда программа должна достичь некоторого определённого результата, использовать или вычисления в контексте, если средства языка позволяют, или коды ошибок, если важна производительность либо язык не позволяет. Исключения, на мой взгляд, особенно неудачны, когда речь идёт о "graceful degradation".
0
Croessmah
++Ͻ
15867 / 8995 / 1728
Регистрация: 27.09.2012
Сообщений: 22,103
Записей в блоге: 2
Завершенные тесты: 2
10.07.2016, 13:05 9
Цитата Сообщение от mporro Посмотреть сообщение
или коды ошибок, если важна производительность
Здесь Вас могут оспорить, конечно,
в зависимости от реализации самого механизма исключений
и реализации других способов обработки ошибок.
По теме: https://habrahabr.ru/post/208006/
Но, имхо, пихать всюду исключения тоже не есть хорошо.
Всё-таки, большую часть проблем можно решить "на месте",
без обращения к "вышеисполняющемуся" коду.
Цитата Сообщение от mporro Посмотреть сообщение
И я всё больше склоняюсь к тому, чтобы использовать исключения только для обрушения программы.
В последнем моем проекте, некий "логический модуль"
после исключения пытается восстановить упавшую часть.
Конечно, если не удается это сделать,
то завершаем работу, ибо дальше нет смысла работать.
Одно из хороший свойств исключений - про них нельзя просто так забыть.
Конечно, можно блок catch пустой оставить, но, это уже сознательный пропуск.
0
mporro
306 / 101 / 18
Регистрация: 04.07.2014
Сообщений: 571
10.07.2016, 13:12 10
Цитата Сообщение от Croessmah Посмотреть сообщение
про них нельзя просто так забыть
Про вычисления в контексте тоже нельзя забыть.
Да и про коды ошибок... Если код правильно организован с логической точки зрения.

А намеренно пропустить можно и исключения, как Вы сами упомянули.
0
Croessmah
++Ͻ
15867 / 8995 / 1728
Регистрация: 27.09.2012
Сообщений: 22,103
Записей в блоге: 2
Завершенные тесты: 2
10.07.2016, 13:15 11
Цитата Сообщение от mporro Посмотреть сообщение
А намеренно пропустить можно и исключения, как Вы сами упомянули.
Вот как раз в последнем проекте так и сделал.
Функция не моя, кидает исключения, зараза, при ошибке.
Но мне её результат не так и важен, можно его просто игнорировать...
пришлось запихнуть в try и пустой catch оставить
(запись в лог всё-таки сделал, правда, пока еще ни разу её там не видел)
0
avgoor
1065 / 619 / 158
Регистрация: 05.12.2015
Сообщений: 1,781
10.07.2016, 15:41 12
Цитата Сообщение от Croessmah Посмотреть сообщение
Всё-таки, большую часть проблем можно решить "на месте"
То, что можно решить на месте - не ошибка, а алгоритм работы.
Ошибка - это когда на одном из уровней (чаще всего на самом нижнем) возникает ситуация на которую непонятно как реагировать и предварительная проверка ничего не дает. В этом случае есть выбор - продолжить работать с наглой мордой, как будто ничего не произошло (как принято на маках) или прекратить работу с сообщением об ошибке.
0
ct0r
Игогошка!
1797 / 704 / 44
Регистрация: 19.08.2012
Сообщений: 1,365
Завершенные тесты: 1
10.07.2016, 16:53 13
Можно замутить монадический стиль обработки ошибок (на основе std::optional) так, как это делается в Haskell, Rust и тд и тп.

Цитата Сообщение от Croessmah Посмотреть сообщение
Одно из хороший свойств исключений - про них нельзя просто так забыть.
У способов обработки ошибок без исключений с этим тоже нет проблем. Более того, они позволяют не забыть про обработку еще на этапе компиляции, а исключения - только после фэйла в рантайме.
0
Croessmah
++Ͻ
15867 / 8995 / 1728
Регистрация: 27.09.2012
Сообщений: 22,103
Записей в блоге: 2
Завершенные тесты: 2
10.07.2016, 17:06 14
Цитата Сообщение от ct0r Посмотреть сообщение
Более того, они позволяют не забыть про обработку еще на этапе компиляции
Угу, а если забыли, то узнаете об этом... эммм... не пойми как.

P.S. Не будем разводить холивар, все делают так, как могут/хотят/требуется.
0
ct0r
Игогошка!
1797 / 704 / 44
Регистрация: 19.08.2012
Сообщений: 1,365
Завершенные тесты: 1
10.07.2016, 17:14 15
Цитата Сообщение от Croessmah Посмотреть сообщение
Угу, а если забыли, то узнаете об этом... эммм... не пойми как.
Легко узнаю. Через ворнинги от компилятора. Привет C++17 и атрибут nodiscard!
0
Croessmah
++Ͻ
15867 / 8995 / 1728
Регистрация: 27.09.2012
Сообщений: 22,103
Записей в блоге: 2
Завершенные тесты: 2
10.07.2016, 17:34 16
Цитата Сообщение от ct0r Посмотреть сообщение
Привет C++17 и атрибут nodiscard!
Еще не приняли же C++17.
Ну и что делать без него?

В общем, обрабатывать ошибки будем так, как велит ситуация
0
ct0r
Игогошка!
1797 / 704 / 44
Регистрация: 19.08.2012
Сообщений: 1,365
Завершенные тесты: 1
10.07.2016, 18:33 17
Croessmah, ждать поддержки компиляторами конечно же! А так уже все определились с тем, что в С++17 будет, а что нет.
nodiscard будет в ближайших релизах, gcc и clang уже имеют его в мастере.
С точки зрения ошибок может быть еще удобна фича structured bindings, но ее еще не делали.

Добавлено через 6 минут
Я вообще про то, что C++ эволюционирует, и казалось бы очевидные и общепринятые подходы к стилю кодирования надо постоянно пересматривать, пробовать что-то новое и тд. Как бы понятно, что всегда я был за исключения, но сейчас вот будет например какая-то адекватная альтернатива - и это хорошо, можно опробовать ее и понять, когда что реально удобно.
1
jupman
230 / 133 / 19
Регистрация: 10.11.2015
Сообщений: 305
05.08.2016, 12:46 18
Цитата Сообщение от mporro Посмотреть сообщение
И я всё больше склоняюсь к тому, чтобы использовать исключения только для обрушения программы.
У меня сейчас выработался такой подход. В случае возврата ошибки из функции/метода делаю запись в лог и роняю прогу. Если по логу разобраться не удалось, изучаю дамп. В функциях/методах которые бросают исключение (new, wcscpy_s etc), в случае ошибки сразу переходим к изучению дампа. Т.е. try/catch я вообще не юзаю. Ну и ничего вроде, привык уже так. Не знаю, может подход нубский, я новичок в c++.
0
hoggy
Эксперт С++
7402 / 3329 / 688
Регистрация: 15.11.2014
Сообщений: 7,614
Завершенные тесты: 1
05.08.2016, 23:13 19
Цитата Сообщение от Убежденный Посмотреть сообщение
3) Не следует пытаться "восстановиться" после какой-то критической ошибки. Самое лучшее и
простое - дать программе просто упасть, сообщив пользователю о том, что произошло, ну возможно
еще снять крэш-дамп и создать логи. Не следует применять здесь какие-то "умные" стратегии,
они все равно будут нелепы.
у нас самолет пассажирский.
отказал двигатель.

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

так мы будем восстанавливаться после паники,
или будем ронять самолет со всеми людьми на борту?

Цитата Сообщение от ct0r Посмотреть сообщение
У способов обработки ошибок без исключений с этим тоже нет проблем. Более того, они позволяют не забыть про обработку еще на этапе компиляции, а исключения - только после фэйла в рантайме.
приведите пример:
как компилятор вежливо напомнит про обработку.

Цитата Сообщение от avgoor Посмотреть сообщение
В этом случае есть выбор - продолжить работать с наглой мордой, как будто ничего не произошло (как принято на маках) или прекратить работу с сообщением об ошибке.
с наглой мордой - это когда ошибка маскируется.

но есть ещё третий вариант:
"строгие гарантии",
с возможностью полного восстановления после паники
(гарантии ликвидации последствий аварии)
1
ct0r
Игогошка!
1797 / 704 / 44
Регистрация: 19.08.2012
Сообщений: 1,365
Завершенные тесты: 1
05.08.2016, 23:28 20
hoggy, я вроде писал уже:
либо просто атрибут nodiscard - тогда ворнинг
либо явный монадический тип в возвращаемом значении (std::optional) - тогда ошибка компиляции
0
05.08.2016, 23:28
Answers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
05.08.2016, 23:28

ряды и способы их обработки
Помогите составить блок схему к програмам program z1; var S,S1:string; i,n:integer; begin...

Способы обработки сообщений windows
Подскажите пожалуйста как называются способы (механизмы) обработки сообщений кроме ловушек

Выборка ошибочных данных, возможна?
Приветствую. :) Имеется таблица: ----------------------------------------------- ...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2019, vBulletin Solutions, Inc.