Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: Давайте поговорим об exeption'ах?  (Прочитано 10001 раз)
0 Пользователей и 4 Гостей смотрят эту тему.
jur
Помогающий

lt
Offline Offline

« : 22-01-2010 18:44 » 

Привет!

Мы постоянно сталкиваемся с ошибками в программах. Иногда их сравнительно легко найти, а иногда бьешься, как рыба об лед, и ни фига... Бывает, что ошибка (как у меня: хендл устройства ввода звука уже удален, а в триде к нему продолжают поступать обращения. И ведь работает программа! В библиотеке WINMM.dll, видать, свой хандлер имеется, вот она и ликвидирует exeption'ы.) выявляется через годы...

Хотелось бы спросить: как грамотно отлавливать ошибки в программе? Имею ввиду те, что порождают предложение послать фирму Микрософт...

Поясню. Моя программа довольно громоздкая. Она использует десятки DLL'ок. Во всех потенциально опасных местах ставить __try/__except/__finally?

Как вообще кошерно обрабатывать исключения? Некоторые из них не опасны, можно просто проигнорировать загрузку данных из "левого" адреса и продолжать работу. А иногда следует программу закрыть, но с обязательным завершением критических тридов. (Иначе при повторном запуске получим сообщение, что программа, типа, уже работает и все, каюк. Только перезагрузка системы...)

Давайте поговорим об этом!

Спасибо!

P.S. Поискал по форуму на тему exeption'ов, но ничего не нашел. (Может плохо искал? Тогда, пожалуйста, направьте.)
Записан

MPEG-4 - в массы!
lapulya
Молодой специалист

ru
Offline Offline

« Ответ #1 : 23-01-2010 02:39 » 

да, в потенциально опасных местах ставить try/catch
Записан

С уважением Lapulya
Вад
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #2 : 23-01-2010 08:24 » 

Поясню. Моя программа довольно громоздкая. Она использует десятки DLL'ок. Во всех потенциально опасных местах ставить __try/__except/__finally?
Что такое "потенциально опасные места"? Если вызываемый код генерирует исключения, то их, безусловно, нужно обрабатывать и ставить try-catch (как-то не привык использовать MS-специфичные аналоги).

Цитата
Как вообще кошерно обрабатывать исключения? Некоторые из них не опасны, можно просто проигнорировать загрузку данных из "левого" адреса и продолжать работу. А иногда следует программу закрыть, но с обязательным завершением критических тридов. (Иначе при повторном запуске получим сообщение, что программа, типа, уже работает и все, каюк. Только перезагрузка системы...)
Вообще, на мой взгляд, исключения, в соответствии с их названием, должны генерироваться в исключительных ситуациях. Например, программа не смогла выполнить какое-то отдельное действие пользователя, и это не фатально, или произошла фатальная ошибка (например, не удалось проинициализироваться полностью - те же dll не удалось подгрузить). В первом случае нужно рассказать пользователю об ошибке и предложить пути к устранению ("не удаётся открыть файл на запись? возможно, он занят другим приложением"), во втором нужно успеть объяснить пользователю, почему дальше работать не получится ("фатальная ошибка: не могу найти такую-то dll")

Исключения стоит обрабатывать всегда. Молча вываливаться по причине необработанного исключения - это просто невежливо со стороны программы. И традиционно учат обрабатывать их там, где их можно обработать. То есть, нужно уметь выделить тот уровень, на котором приложение компетентно обработать ошибку. Нужно ответить на вопрос: насколько ошибка является критичной, и какую часть операций не имеет смысла продолжать после сбоя.

Например, нам нужно выполнить какие-то действия над файлом: открыть, прочитать и обработать данные. Если не удаётся открыть файл, то нет никакого смысла продолжать работу с данными (которых просто нет). Соответственно, исключение должно перехватываться где-то на уровень выше функций "открыть"-"прочитать"-"обработать". На нижних уровнях имеет смысл разве что транслировать исключение в другое исключение, чтобы накопить больше информации о сбое и как можно более конкретно обработать его на основе этой информации. Ну, и выполнять какие-то действия по освобождению ресурсов, если они больше не потребуются (хотя это по возможности лучше делать автоматически)
« Последнее редактирование: 23-01-2010 08:29 от Вад » Записан
jur
Помогающий

lt
Offline Offline

« Ответ #3 : 23-01-2010 08:50 » 

да, в потенциально опасных местах ставить try/catch

Ёлки, до фига мест получится...

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

Что такое "потенциально опасные места"? Если вызываемый код генерирует исключения, то их, безусловно, нужно обрабатывать и ставить try-catch (как-то не привык использовать MS-специфичные аналоги).

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

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

Исключения стоит обрабатывать всегда. Молча вываливаться по причине необработанного исключения - это просто невежливо со стороны программы. И традиционно учат обрабатывать их там, где их можно обработать. То есть, нужно уметь выделить тот уровень, на котором приложение компетентно обработать ошибку. Нужно ответить на вопрос: насколько ошибка является критичной, и какую часть операций не имеет смысла продолжать после сбоя.

Абсолютно справедливо! Поэтому я и хочу научиться правильно использовать эту технику. (Лучше очень, очень поздно, чем вообще никогда :-)

Может быть можно было бы сформулировать какие-нить "правила хорошего тона" для грамотного и корректного отлова ошибок?

К примеру, для программирования под Вижуал Студией правила такие:

1. В потенциально опасных местах использовать блоки __try/__except/__finally (или try/catch).

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

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

4. ...

Чего бы еще сюда дописать, или что бы скорректировать?
Записан

MPEG-4 - в массы!
Вад
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #4 : 23-01-2010 09:59 » 

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

По п. 1: нужно чётко понимать, что "опасные места" - это можно сделать по одному try-except на каждый вызов, а можно сделать один общий на несколько, если выполняется набор операций, некоторые из которых могут бросить исключения, и имеет смысл прервать всю последовательность. Или пробросить исключение наверх, потому что ошибка на одном из этапов может повлечь ошибку где-то выше. И так можно дойти до того, что останется один общий "глобальный обработчик"

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

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

По пункту 3. На самом деле, C++ предлагает некоторые техники (а мэтры вроде Майерса понаторели в описании таких техник) сделать код как можно безопаснее с т.з. исключений. То есть, чтобы исключения не приводили к утечкам ресурсов. Например, реализация идиомы RAII позволяет автоматически освобождать захваченные ресурсы при раскрутке стека во время исключения. А следование некоторым вспомогательным правилам позволяет безопасно использовать эту идиому в некоторых специфических ситуациях (таких, как передача нескольких ресурсов-аргументов в функцию).
Записан
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #5 : 23-01-2010 11:58 » new

Помнится, в SharePoint отсутствие перехвата исключений в WebPart благополучно валило вообще весь сервер. Поэтому в случае написания каких-то plugin'ов или частей для чужих framework'ов вежливо будет строго соблюдать интерфейс в части исключительных ситуаций, и если в интерфейсе такие ситуации не заявлены, то не пропускать их.
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
jur
Помогающий

lt
Offline Offline

« Ответ #6 : 03-02-2010 19:23 » 

Привет!

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

Конкретный случай. Я применяю широко известную (и превосходную!) библиотеку FFTW. Как полагается, завел класс, посоздавал в нем множество всяческих массивов. Далее следуют так называемые планы - это такая фигня, которую создает сама библиотека, некая база данных, позволяющая ей оптимально производить вычисления.

Запускаю - получаю фатальную ошибку... Попытку выполнить процессорную инструкцию по адресу 8... Смотрю стек вызовов, а там некий ассемблерный код (типа call edx), который на самом деле вызывает черт знает что. Перед ним следуют неоднократные вызовы из NTDLL.DLL. Все.

Долго думал... После мучительных раздумий понял, что это я ошибся в формировании выходного массива и пишу за его пределы (тем самым затирая эти самые планы, в которых, по всей видимости, как раз и хранятся адреса функций для вызова).

Куды бечь? За что хвататься? - Ума не приложу...

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

Это каким-то образом возможно? Типа того, что принудительно передаешь не только адрес массива для записи, но и его размер (или старший адрес записи/чтения, что одно и то же).
Записан

MPEG-4 - в массы!
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #7 : 03-02-2010 20:52 » 

jur, не повторяй вопросы, туда иди: https://forum.shelek.ru/index.php/topic,23342.0.html
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
jur
Помогающий

lt
Offline Offline

« Ответ #8 : 04-02-2010 11:44 » 

Прошу прощения. Я не заметил, что тема перенесена. Иду туда.
Записан

MPEG-4 - в массы!
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines