Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Вопрос про работу эксепшенов [XP]


cyber-pilot ©   (2011-01-20 14:25:00) 

Есть следующий код:

procedure TForm1.Button1Click(Sender: TObject);
var
 vSL: TStringList;
begin
 try
   try
     vSL.CommaText := '';
   except
     on E: Exception do
     begin
       E.Message := 'Msg1: ' + E.Message;
       raise;
     end;
   end;
 except
   on E: Exception do
   begin
     E.Message := 'Msg2: ' + E.Message;
     ShowMessage(E.Message);
     raise;
   end;
 end;
end;


Я всегда думал, что если писать таким образом, то к сообщения будут склеиваться. В этом же случае происходит Access Violation и информация о добавленных строчка почему-то теряется. Это так специально сделано или глюк Делфи?
Проверял в Delphi 2007 и Delphi XE.


cyber-pilot   (2011-01-21 14:35:00) [1]


>  Ega23 ©   (20.01.11 16:37) [16]


> DiamondShark ©   (21.01.11 01:08) [17]

Понятно. Спасибо!


KSergey   (2011-01-21 09:48:00) [2]

> Игорь Шевченко ©   (20.01.11 16:31) [15]

Не могли бы вы сказать ответ? :)
Вроде с виду код как у меня.

Или предлагается попробовать и оценить эффект?


DiamondShark   (2011-01-21 01:19:00) [3]


> DiamondShark ©   (21.01.11 01:08) [17]

Впрочем, не только аппаратные ловушки, а вообще все исключения, порождённые операционной системой.
Все эти исключения имеют базовым классом EExternal.


DiamondShark   (2011-01-21 01:08:00) [4]


>  Это так специально сделано или глюк Делфи?

Это специально так сделано.
Исключения, которые генерируются в ответ на аппаратные ловушки пересоздаются.
Программные исключения используют тот же экземпляр.


var
 P: ^Integer;
 a, b: double;
 i, j: integer;
begin
 P := nil;
 a := 0;
 b := 0;
 i := 0;
 j := 0;
 try
   try
// раскоментировать по вкусу
//      raise EAccessViolation.Create('koo!'); // один и тот же экземляр
//      raise Exception.Create('qwe'); // один и тот же экземляр
//      i := i div j; // разные экземпляры
//      writeln(i); // чтоб оптимизатор код не выкинул
//      a := a / b; // разные экземпляры
//      writeln(a); // чтоб оптимизатор код не выкинул
//      P^ := 1; // разные экземпляры
   except
     on E: Exception do
     begin
       E.Message := 'Msg1: ' + E.Message;
       ShowMessage(IntToStr(Integer(E)));
       raise;
     end;
   end;
 except
   on E: Exception do
   begin
     E.Message := 'Msg2: ' + E.Message;
     ShowMessage(IntToStr(Integer(E)));
   end;
 end;
end;


Ega23   (2011-01-20 16:37:00) [5]


> А вот для AccessViolation не срабатывает.


EAccessViolation is raised when an application:

Dereferences a nil (Delphi) or NULL (C++) pointer.
Writes to memory reserved for executable code.
Attempts to access a memory address for which there is no virtual memory allocated to the application.
Run-time exception information is saved in fields provided by EExternal.

Note:  Applications should not raise EAccessViolation directly, but should instead rely on the run time to raise this exception.


Игорь Шевченко   (2011-01-20 16:31:00) [6]

KSergey ©   (20.01.11 15:48) [7]

procedure raiseOOM;
begin
 raise EOutOfMemory.Create ('gothca');
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
 try
   raiseOOM;
 except
   on E: Exception do
   begin
     E.Message := 'Foo';
     raise E;
   end;
 end;
end;


Anatoly Podgoretsky   (2011-01-20 16:18:00) [7]

> KSergey  (20.01.2011 15:48:07)  [7]

Нельзя, справа должен быть объект, а не текст.


Ega23   (2011-01-20 16:10:00) [8]


>  и доказывает, Palladin ©   (20.01.11 14:34) [2] - не правда.


Доказывает. Это два разных объектаодного и того же класса.
Есть класс, а есть экземпляр класса. Класс - один, экземпляров - от нуля до Over9000
Соответственно, в [8] проверяется принадлежность E к EZeroDivide и EConverError, после чего подымаются аналогичные по классу исключения.
Третий случай - для всех остальных классов, аналог else в case.
А на втором обработчике перехватываются уже любые исключения.


Palladin   (2011-01-20 16:09:00) [9]

Не понял, что доказывает?

try
  try
    vSL.CommaText := '';
  except
    on E: Exception do
    begin
      E.Message := 'Msg1: ' + E.Message;
      ShowMessage(IntToStr(Integer(E)));
      raise;
    end;
  end;
except
  on E: Exception do
  begin
    E.Message := 'Msg2: ' + E.Message;
    ShowMessage(IntToStr(Integer(E)));
  end;
end;

удивись


cyber-pilot   (2011-01-20 15:59:00) [10]


> Ega23 ©   (20.01.11 15:53) [8]

Да, это мне и нужно. И обычно так все и работает, и доказывает, Palladin ©   (20.01.11 14:34) [2] - не правда.
А вот для AccessViolation не срабатывает.


Palladin   (2011-01-20 15:55:00) [11]

нет


Ega23   (2011-01-20 15:55:00) [12]


> KSergey ©   (20.01.11 15:48) [7]
>
> А вот так можно?


А конструктор кто вызывать будет?


Ega23   (2011-01-20 15:53:00) [13]

А, я понял что тебе нужно.
Вроде как в общем случае решения нет. Тебе нужно чётко знать класс исключения. Что-то типа


procedure TForm4.Button1Click(Sender: TObject);
begin
 try
   try
     ShowMessage(FloatToStr(5/StrtoInt(Edit1.Text)))
   except
    on E: EConvertError do raise EConvertError.Create('Первый обработчик' + #13#10 + E.Message);
     on E: EZeroDivide do raise EZeroDivide.Create('Первый обработчик' + #13#10 + E.Message);
     on E: Exception do raise Exception.Create('Первый обработчик (а фиг знает)' + #13#10 + E.Message);
   end;
 except on E: Exception do
   ShowMessage('Второй обработчик' + #13#10 + E.Message);
 end;
end;


KSergey   (2011-01-20 15:48:00) [14]

Вопрос у меня чайника:
А вот так можно?

try
....
except on E: Exception do
   E.Message := .....
   raise E;
end;


Palladin   (2011-01-20 15:33:00) [15]


> Я всегда считал, что это один и тот же объект.

я не знаю какая религия это исповедует


Ega23   (2011-01-20 15:27:00) [16]


> Но при этом в обработчике более высокого уровня я не смогу
> узнать какой тип эксепшена произошел в действительности.
>  То есть не получится написать on EOutOfMemory do.


Нет проблем:

try
....
except on E: Exception do
raise Exception.Create('bla-bla-bla  ' +#13#10 + E.ClassName + #13#10 +  E.Message);
end;


cyber-pilot   (2011-01-20 15:24:00) [17]


> Palladin ©   (20.01.11 14:34) [2]
>
> E уровнем ниже не есть E уровнем выше. это два разных объекта

Я всегда считал, что это один и тот же объект.


> 1. Чтобы "склеивалось" делается так:
> try
>  ....
> except on E: Exception do
>  raise Exception.Create('bla-bla-bla  ' + E.Message);
> end;

Но при этом в обработчике более высокого уровня я не смогу узнать какой тип эксепшена произошел в действительности. То есть не получится написать on EOutOfMemory do.


> 2. AV получаешь закономерно, ибо обращаешься к свойству
> несозданного объекта vSL.CommaText := '';

Это я специально написал, чтобы ошибку вызвать.


Ega23   (2011-01-20 14:35:00) [18]


> Я всегда думал, что если писать таким образом, то к сообщения
> будут склеиваться.


1. Чтобы "склеивалось" делается так:
try
 ....
except on E: Exception do
 raise Exception.Create('bla-bla-bla  ' + E.Message);
end;


2. AV получаешь закономерно, ибо обращаешься к свойству несозданного объекта vSL.CommaText := '';
Надо так:
vSL := TStringList.Create;
try
 try
   vSL.CommaText := '';
   .....
 except on E: Exception do
   raise Exception.Create('bla-bla-bla  ' + E.Message);
 end;
finally
 vSL.Free;
end;


Palladin   (2011-01-20 14:34:00) [19]

E уровнем ниже не есть E уровнем выше. это два разных объекта


Dennis I. Komarov   (2011-01-20 14:31:00) [20]

Глюков нет. Работает так как надо.

А чего там где недоприлипло, я не понял...


Наверх

Титульная страница Поиск, карта сайта Написать письмо