svk12 писал(а):Если ошибка произойдёт в цикле, то перед выдачей сообщения RTL выполнит выход из цикла и программа не зависнет.
Для проверки на nil есть функция Assigned
Статистика: Добавлено А.Н. — 29.08.2010 21:03:04
Код:
try
.........
except on E:Exception do
endСтатистика: Добавлено svk12 — 07.08.2010 11:27:04
А.Н. писал(а):Там описано одно исключение из правила:
А.Н. писал(а):Не, я имел ввиду не отдельный метод, вызываемый в цикле. А метод объекта, обрабатываемого в цикле. Т.е., всё в методе обёрнуто try/except и он возвращает false/nil и т.д., в случае неудачи.
В принципе, как-то привычно, но, по-идее, неправильно?
Код:
if not LoadFile(AFilename) then CreateFile(AFilename);А.Н. писал(а):Т.е., всё сводится к тому, чтобы пропускать все ошибки, а по мере появления, писать их обработчики?
А.Н. писал(а):В смысле, в RunLoop проще?
А.Н. писал(а):Т.е., просто сделать общий обработчик, который вызовет raise, в случае отсутствия обработчика для конкретного исключения? Сложный он получается...
А.Н. писал(а):Хм... А есть какие-то готовые решения для обработки исключений, типа какой-нибудь библиотеки для работы с ними?
Статистика: Добавлено Odyssey — 07.08.2010 11:04:12
Если ему не хватило памяти на то чтобы вставить кусок текста, совсем не факт, что в таких экстремальных условиях ему удасться сбросить отчёт на диск. А даже если удасться, лучше этих условий не ждать, а сделать всё заблаговременно.
Что же до самоустранения, то это вопрос "чуства собственного величия" программы, если этот термин применим к программам.
Если система докатилась до того, что даже блокноту не может выделить памяти, значит ей очень нехорошо. И в таких условиях лучше отдать ресурсы тем, кому они реально нужны, иначе ОС может навернуться вместе с нашим блокнотом.
ИМХО, обработка ситуации нехватки памяти без самоустранения целесообразна только тогда, когда остановка программы приводит к катастрофе. На десктопе, имхо, таких ситуаций нет.
Если имеется в виду try ... except end; то ничего такого в статье не написано!
The only time that you might even consider using this construct – which is only slightly better than eating the exception altogether is -- when you know that the calling routine doesn't want to handle any exceptions or when the calling routine expects to handle the specific exception. For instance, the TClientDataset has an OnReconcileError event that actually passes an exception into it. If you were doing some batch processing with a Clientdataset, then allowing this exception to bubble up the stack will stop the loop. In this case, you might want to generically trap all the exceptions that are passed into the event handler.
Можно и в методе, я написал пример прямо в цикле из-за лени, чтобы не писать метод.
А OnException это тоже разновидность обработчика.
Есть случаи когда нельзя продолжать беззаботно перебирать элементы как будто ничего не случилось. Поэтому смысл в том, чтобы обработать конкретные, относительно безопасные, "штатные" типы ошибок, а со всеми внештатными поступать по общему правилу для внештатных (например "лог, сообщение, завершение работы", или вообще для начала оставить обработку по умолчанию).
Хотя наверное даже это усложнено, и в RunLoop проще. Тут лучше посмотреть исходники FPC/Lazarus.
Статистика: Добавлено А.Н. — 05.08.2010 21:54:37
Если имеется в виду try ... except end; то ничего такого в статье не написано! Как раз наоборот, Trap only specific exceptions, т.е. между except и end должна быть обработка с определением типа.А.Н. писал(а):про что в той статье сказано: пустая обёртка try/except допустима
Можно и в методе, я написал пример прямо в цикле из-за лени, чтобы не писать метод.А.Н. писал(а):почему не сделать обёртку в методе, а не в цикле?
Не знаю, я таких обработчиков не писалВедь нельзя же восстановить работоспособное состояние программы не зная её структуры.А.Н. писал(а):Т.е., получается, что обработчик очень сложный? Этакая "программа в программе"?
А OnException это тоже разновидность обработчика. За каждым OnException скрывается что-то типаА.Н. писал(а):Ну, это возможно и в OnException сделать. Для этого не нужен такой обработчик.
Код:
procedure TApplication.RunLoop;
begin
repeat
if CaptureExceptions then
try // run with try..except
HandleMessage;
except
HandleException(Self);
end
else
HandleMessage; // run without try..except
until Terminated;
end;Все -- нельзя, да это и не нужно. Например нам не хватает памяти на очередной запрос, или возникла проблема соединения с БД, и мы пытаемся подключиться к упавшему хосту с тремя попытками и таймаутом 1 минута на каждый элемент. Есть случаи когда нельзя продолжать беззаботно перебирать элементы как будто ничего не случилось. Поэтому смысл в том, чтобы обработать конкретные, относительно безопасные, "штатные" типы ошибок, а со всеми внештатными поступать по общему правилу для внештатных (например "лог, сообщение, завершение работы", или вообще для начала оставить обработку по умолчанию).А.Н. писал(а):Это красиво выглядит в примере. На самом деле, здесь, как мне кажется, есть неоднозначность. Во-первых, реальный код сложнее. Например, занесение в БД. Если произошла ошибка, при занесении - проблема элемента. Если это внешняя ошибка, например ОС - проблема вышестоящего уровня.
Но ведь нельзя все ошибки выделить, даже если использовать базовые классы исключений?
Да, общий. А чтобы не повторять код, можно вынести обработчик в отдельную функцию, по аналогии с HandleException в TApplication.RunLoop. Мне ещё приходит в голову что типа:А.Н. писал(а):К тому же, во всех классах, если их много, делать блок try/except, который учитывает все эти ситуации, повторяя код? Так что получается? Здесь и нужен общий обработчик? Или как-то нужно эту обработку реализовать в базовом классе?
Код:
try
...
except
on E do
begin
if not MyHandleException(E) then raise;
end;
end;
Статистика: Добавлено Odyssey — 05.08.2010 20:29:56
Зависит от того, что нужно делать, и где можно это сделать. Чем глобальнее, тем наверное лучше (чище код)
но иногда в "общем обработчике на всю программу" уже нет доступа к объектам, которые помогли бы восстановиться после исключения. Тогда придётся делать обработку там, где такой доступ есть.
Ох, зря я про неё вспомнил![]()
Просто больше не пришло в голову ни одного случая, когда можно восстановиться после нехватки ресурсов. Вообще, нехватка ресурсов -- это такая штука, что если приложение о ней узнало, должно не восстанавливаться, а самоустраниться как можно быстрее, чтобы освободить ресурсы.
Если это конечно не АСУ на АЭС.
А.Н. писал(а):в точку вызова
Насколько знаю, это невозможно. После exception'а можно попасть только в обрачивающие блоки except/finally, и назад пути нет. Поэтому их и приходится размещать там, где ещё можно восстановиться, если в восстановлении есть смысл.
А.Н. писал(а):Т.е., обработчик должен знать много о структуре программы?
Если его назначение -- спасти ситуацию, то да. Ведь нельзя же восстановить работоспособное состояние программы не зная её структуры.
Если назначение -- выкинуть сообщение в лог, уведомить пользователя об ошибке и закрыть программу -- то можно и не знать о структуре.
А.Н. писал(а):Нужно определять к какому классу исключений оно относится?
Точно.
...
Допустим в цикле вызывается некая процедура HandleItem, которая умеет обрабатывать элементы всех типов кроме одного, и в случае этого "одного" вызывает исключение EWrongItemType. Тогда код цикла может выглядеть примерно так:
Статистика: Добавлено А.Н. — 05.08.2010 17:59:48
Ох, зря я про неё вспомнилА.Н. писал(а):Хм... Вот, только вы вспомнили про многопоточность... :- Да и как будет выглядеть этот обработчик? Не слишком сложно?
Насколько знаю, это невозможно. После exception'а можно попасть только в обрачивающие блоки except/finally, и назад пути нет. Поэтому их и приходится размещать там, где ещё можно восстановиться, если в восстановлении есть смысл.А.Н. писал(а):Плюс к тому, надо вернуться из обработки исключения, если она прошла, в точку вызова.
Если его назначение -- спасти ситуацию, то да. Ведь нельзя же восстановить работоспособное состояние программы не зная её структуры. Если назначение -- выкинуть сообщение в лог, уведомить пользователя об ошибке и закрыть программу -- то можно и не знать о структуре.А.Н. писал(а):Т.е., обработчик должен знать много о структуре программы?
Мда, с нехваткой ресурсов плохой пример. Я тут имел в виду примерно то, что написано в статье Ника с примеромА.Н. писал(а):Каким образом? См. выше.Odyssey писал(а):Т.е. если ловим исключение о нехватке русурсов, в обработке освобждаем ресурсы
Код:
try
SomeCodeThatRaisesAnEConvertError;
except
on E: EConvertError do
begin
// Deal with this specific exception here
end;
end;
Код:
for i := 0 to List.Count - 1 do
begin
try
HandleItem(List[i])
except
// только так:
on EWrongItemType do MarkItemAsUnhandled(List[i]);
// но не так:
// MarkItemAsUnhandled(List[i]);
end;
end;
Точно.А.Н. писал(а):Есть два варианта:
1. Это проблема элемента.
2. Это другая проблема. Какое-то внешнее исключение.
В первом случае, надо продолжить цикл, пропустив элемент. Во-втором - завершить программу или что-то сделать. Нужно определять к какому классу исключений оно относится?
Статистика: Добавлено Odyssey — 02.08.2010 14:39:13
Но опять же, нельзя ловить произвольный Exception (т.е. try .. except без on ..do), потому что его по определению нельзя обработать правильно, ведь неизвестно из-за чего он возник. Т.е. если ловим исключение о нехватке русурсов, в обработке освобждаем ресурсы
Odyssey писал(а):если исключение другое -- нужно его снова перегенерировать, чтобы не прошло незамеченным.
MageSlayer писал(а):Все должно работать без оборачивания пустыми try-except.
MageSlayer писал(а):Во-первых, с формами, создающимися динамически, вообще работать не будет. Вы будете хранить указатели/объекты, которых уже может не быть "в живых".
Во-вторых, как вам уже советовали, здесь нужно плясать от функциональности самих форм, а не пытаться запихнуть их в несвойственное им окружение. То есть, или наследовать их все от общего предка с функциональностью сокрытия, или цепляться к ним через события, или "подмешивать" функциональность через интерфейсы.
Через события, конечно хуже, т.е. они уже могут использоваться другой функциональностью.
(жлобское выражение, сорри)
Тут из небыстрых решений - перейти на VirtualTreeView + интерфейсы.
Обычно это проблема смешения бизнес-логики (жлобское выражение, сорри) и собственно отрисовки/визуализации/...
Опять же, если визуализация тесно переплетена с "бизнес-логикой", то это тупик. Раньше или позже.
И исключения или их иерархия, имхо, никак не помогут. Не для того, они созданы.
Если нет ресурсов, то программа должна поймать исключение на самом верхнем уровне. И по дороге корректно разрушить все временных объекты.
krab писал(а):О исключениях. Даже о использовании в цикле обработки упоминается:
Код:
Result := True;
try
Temp := StrToInt(aStr);
except
Result := False;
end;
Статистика: Добавлено А.Н. — 02.08.2010 10:44:51
If you were doing some batch processing with a Clientdataset, then allowing this exception to bubble up the stack will stop the loop. In this case, you might want to generically trap all the exceptions that are passed into the event handler.
Статистика: Добавлено krab — 02.08.2010 01:34:31
А.Н. писал(а):Про тонну проверок опять не понял. Может все-таки по-подробнее?
Пример там же: if (form = nil) then continue;
Ну, или в таком стиле:Код:
if (blank = nil) then
// Если такой бланк не учтён, я добавляю его в коллекцию.
begin
blank := ins_comp.BlankAdd(entity_id[1], entity_id[2]);
if (blank = nil) then exit;
...
ins_comp := TInfInsCompany(CompaniesCollection.GetEntityByID(entity_id));
if (ins_comp = nil) then exit;
t_node := trvLeft.Items.FindNodeWithData(ins_comp);
// 1. Удаляю из дерева.
if (t_node <> nil) then t_node.Free;
// 2. Удаляю из коллекции.
ins_comp.Free;
Это слегка загромождает код. Но без этих проверок я слегка получаю SIGSEGV.
Поэтому, привык уже делать.
Но, ведь, по-идее, это за меня должна делать иерархия исключений?
А.Н. писал(а):Добавлено спустя 3 минуты 46 секунд:
Короче, я запутался с тем, где исключения должны выбрасываться.
Например, при ошибке во время создания объекта выбрасывается исключение?
Например, если недостаточно ресурсов. И что тогда делать? С исключением - он повесится.
Без исключения хоть как-то может работать. И что получается, для этого нужно загнать его в функцию, обернуть пустым try/except и проверить результат на NULL в вызывающем? Зачем тогда исключения?
А.Н. писал(а):Добавлено спустя 1 минуту 27 секунд:
Хм... Ещё, почему-то у меня возникает ощущение, что я порю несусветный бред.
Статистика: Добавлено MageSlayer — 01.08.2010 23:26:56
Статистика: Добавлено Odyssey — 01.08.2010 23:25:11
Про тонну проверок опять не понял. Может все-таки по-подробнее?
Код:
if (blank = nil) then
// Если такой бланк не учтён, я добавляю его в коллекцию.
begin
blank := ins_comp.BlankAdd(entity_id[1], entity_id[2]);
if (blank = nil) then exit;
...
ins_comp := TInfInsCompany(CompaniesCollection.GetEntityByID(entity_id));
if (ins_comp = nil) then exit;
t_node := trvLeft.Items.FindNodeWithData(ins_comp);
// 1. Удаляю из дерева.
if (t_node <> nil) then t_node.Free;
// 2. Удаляю из коллекции.
ins_comp.Free;
Статистика: Добавлено А.Н. — 01.08.2010 22:58:35
Статистика: Добавлено MageSlayer — 01.08.2010 22:35:50
Статистика: Добавлено krab — 01.08.2010 22:28:15
Статистика: Добавлено А.Н. — 01.08.2010 19:52:14
Код:
while Condition do
begin
try
// ...
except
on E: YourException do
begin
// обработка
end;
end;
end;А.Н. писал(а):Приходится оборачивать пустыми try/except.
Статистика: Добавлено krab — 01.08.2010 19:25:43
Статистика: Добавлено MageSlayer — 01.08.2010 19:13:12
Статистика: Добавлено А.Н. — 01.08.2010 18:33:09
Статистика: Добавлено hinst — 31.07.2010 21:17:47
Статистика: Добавлено А.Н. — 31.07.2010 21:00:58
Статистика: Добавлено Mr.Smart — 30.07.2010 21:27:04
Код:
raise Exception.Create('Error message');Статистика: Добавлено krab — 30.07.2010 21:13:41
Код:
raise Exception.Create('Error message');Статистика: Добавлено Odyssey — 30.07.2010 20:56:33
MageSlayer писал(а):Э-э.
Стандартный?
Ну, исключения, или просто код возврата. Лишние глобальные переменные, имхо, никчему.
Статистика: Добавлено MageSlayer — 30.07.2010 20:49:49
Статистика: Добавлено krab — 30.07.2010 20:46:58
Статистика: Добавлено MageSlayer — 30.07.2010 20:37:08
Статистика: Добавлено krab — 30.07.2010 17:58:35