Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Для новичков > Создание объекта, AV


Автор: Rohoss 20.6.2008, 01:15
Код

MyClass := TComponent.Create(Self);
try

finally
  MyClass.Free;
end;

Это стандартный шаблон кода, входящий в состав среды Delphi 2006, который можно выбрать нажатием плавишь Ctrl + J. Почему объект создаётся перед блоком try, а не внутри него? smile 

Автор: Beltar 20.6.2008, 09:42
Помнится на DelphiKingdom в разделе "Свитки" были статейки на тему безопасности языков программирования, где как раз и обсуждались обломы в конструкторе и многое другое.

Статьи назывались: "ЯП, ОПП и т.д. и т.п. в свете безопасности программирования" http://www.delphikingdom.ru/asp/viewitem.asp?catalogid=301 всего 4 части и ответ на нее "Игра отражений" http://www.delphikingdom.ru/asp/viewitem.asp?catalogid=346.

Автор: pseud 20.6.2008, 09:51
Цитата(Rohoss @  20.6.2008,  01:15 Найти цитируемый пост)
 Почему объект создаётся перед блоком try, а не внутри него?  


потому что 
Код

TComponent.Create

может отработать с ошибками и в MyClass у тебя останется nil. И в итоге ты обратишься в MyClass.Free к методу несуществующего объекта и получишь AV

Автор: Beltar 20.6.2008, 10:36
Цитата

И в итоге ты обратишься в MyClass.Free к методу несуществующего объекта и получишь AV


Причем здесь это? Все равно Free будет вызвано, и если Create не отработал, то ты получишь AV. А конструктор в try запихивать не надо, потому что он по умолчанию в защищенном блоке работает. Так что шаблон вполне логичный.

Автор: pseud 20.6.2008, 10:54
Цитата(Beltar @  20.6.2008,  10:36 Найти цитируемый пост)
Причем здесь это? Все равно Free будет вызвано, и если Create не отработал, то ты получишь AV.

именно так я и написал....

Цитата(Beltar @  20.6.2008,  10:36 Найти цитируемый пост)
 А конструктор в try запихивать не надо, потому что он по умолчанию в защищенном блоке работает

интересно в каком защищенном блоке работает constructor в примере?
Код

constructor TMyClass.Create(AOwner: TComponent);
begin
  raise Exception.Create('ой');
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  c: TMyClass;
begin
  c := TMyClass.Create(Self);
  try
  finally
    c.Free;
  end;
end;

Автор: Beltar 20.6.2008, 17:11
Ссылки выше. "Игра отражений" Не забываем, что Create это не только и не столько конструктор, написанный разработчиком класса.
Присваивание же переменной nil это самое логичное поведение при сбое, которое легко проверить без try.

Автор: Rohoss 22.6.2008, 04:57
Так, что ли?
Код

MyClass := TComponent.Create(Self);
if MyClass=nil then Exit;
try

finally
  MyClass.Free;
end;

А зачем тогда try finally? Если у кого то есть рабочий пример использования, пожалуйста приведите с пояснениями. smile 

Автор: MetalFan 22.6.2008, 09:55
Цитата(Rohoss @  22.6.2008,  04:57 Найти цитируемый пост)
Так, что ли?

не так.

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

Rohoss, проверка во 2й строке не имеет смысла, ибо в случае исключения в конструкторе мы на нее не попадем, соотв. если исключение не возникнет, то и условие не выполнится.

Пример:
Код

var
  lPtr: pointer;
  lObj: TObject;
begin
  GetMem( lPtr, SomeSize );
  try //при любом раскладе гарантируем освобождение ресурсов
    ...
    if Condition then exit; //выход, но не из функции, а в секцию finally
    ...
    lObj.Property := Value; //ловим AV, но сначала в finally!
  finally 
    FreeMem( lPtr );
  end;

Автор: Rohoss 22.6.2008, 10:29
Так почему мы попадём в секцию finaly, если исключение возникнет при выделении памяти, до блока try?

Код

var
  lPtr: pointer;
  lObj: TObject;
begin
  GetMem( lPtr, SomeSize ); //Возникает АV, но почему оно обрабатывается?  Оно же возникло перед try
  try 
    ...
    if Condition then exit; 
    ...
    lObj.Property := Value; 
  finally 
    FreeMem( lPtr );
  end;

Автор: Rrader 22.6.2008, 10:38
А мы туда не попадем. Если исключение (reOutOfMemory) сгенерится в GetMem, память просто не будет выделена, а NIL и освобождать не нужно. Но мы и не дойдем до try-finally-end. Тут речь о том, что блок try-finally-end позволяет гарантированно освобождать валидные ресурсы.

Вот, final-версия этого поста smile 

Автор: Rohoss 22.6.2008, 10:42
Так этот блок не обрабатывает исключений в конструкторе объекта?
Я имею ввиду то, что в конструкторе, помимо выделения памяти может много ещё чего содержатся. 

А если всё же память будет равна nil, мы перейдём в блок try, с него естественно в finaly, а там MyClass.Free , обращение к методу несуществующего класса…
Сори за такие вопросы, просто хочу понять, как это работает…

Автор: Rrader 22.6.2008, 10:53
1. Обо всех опасных действиях в конструкторе нужно заботиться самостоятельно и защищать их теми же try-finally-end.

2. Возникает исключение в конструкторе. Если все находится в правильно оформленном защищенном SEH-блоке(try-finally-end), то ресурсы гарантированно освободятся. Что происходит потом? А ничего, выход.

Смотри:
Код

procedure TForm1.Button1Click(Sender: TObject);
var
  F: TFileStream;
begin
  F := TFileStream.Create('NIL', fmOpenReadWrite);
  try
    F.Seek(0, soFromEnd);
  finally
    F.Free;
  end;
end;

Так вот здесь мы не дойдем до Seek никогда. Понятно теперь? smile 

Автор: Rohoss 22.6.2008, 10:55
Rrader , тебе не надоело редактировать своё сообщение, пиши нове, а то хз что получается.  smile 

Автор: Rrader 22.6.2008, 10:58
Rohoss, это чтоб понятнее было исправлял =)
Вот тебе еще пример:
Код

procedure TForm1.Button1Click(Sender: TObject);
var
  P: Pointer;
begin
  GetMem(P, 100000000000);
  try
     P := 0;
  finally
     FreeMem(P);
  end;
end;

До FreeMem дело не дойдет, даже до try не дойдет, если будет ошибка Out Of Memory.

Автор: Rohoss 22.6.2008, 11:04
Угу, ну тогда всё логично. Просто я почему то думал что этот блок защищает и от ошибок конструктора…

Автор: MetalFan 22.6.2008, 11:08
Цитата(Rohoss @  22.6.2008,  10:42 Найти цитируемый пост)
А если всё же память будет равна nil, мы перейдём в блок try, с него естественно в finaly, а там MyClass.Free 

и ничего страшного не произойдет (конечно после конструктора переменная класса всегда <> nil, кроме случаев возникновения исключения в конструкторе). Free тем от Destroy и отличается, что проверяет Self<>nil. так что конструкции типа
Код

  if Assigned(lSomeObject) then
    lSomeObject.Free;

смысла не имеют никакого.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)