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


Автор: Andreyzpr 30.9.2007, 11:20
Не могу понять, что делает try и finally
Кто нибудь может рассказать для чего эти команды служат и что делают?

Автор: MetalFan 30.9.2007, 11:35
обеспечивает выполнение кода finally-end даже если произошла ошибка между try-finally
используется например для 99,9% освобождения захваченных ресурсов.
Код


...
  lFileStream := TFileStream.Create(...)
  try
    lFileStream.xxxx
....
  finally
    lFileStream.Free;
  end;

в данном случае при возникновении ошибки между try-finally файл будет закрыт и память под объект будет освобождена

Автор: EvilsInterrupt 30.9.2007, 12:23
Назначение, небольшие нюансы по исключениям.

Речь пойдет о конструкциях вида: try-finally-end; , try-except-end
1. Синтаксис.
Код

try
// попытка выполнить
finally
// завершающие действия
end;


Код

try
// Попытка выполнить
except
// Выполнить обработку ошибки или попытаться исправить ситуацию
end;


2. Работа конструкций.
Что происходит в случае применения конструкций?

Для того чтобы понять, что же происходит создадим прогу, добавим форму и кнопку, потом добавим ее обработчик с таким кодом:
Код

  procedure TfrmMain.Button1Click(Sender: TObject);
  var
    tmp,tmp2 : TCriticalSection;
  begin
    tmp := Nil;
    tmp2 := Nil;    
    try
      try
//        tmp := TCriticalSection.Create;
        tmp.Acquire;
        Memo1.Lines.Add('tmp');
        tmp.Release;
      finally
        Memo1.Lines.Add('finally1');
      end;
      try
        tmp2 := TCriticalSection.Create;
        tmp2.Acquire;
        Memo1.Lines.Add('tmp2');
        tmp2.Release;
      finally
        Memo1.Lines.Add('finally2');
      end;
    except
      on E : Exception do
         Memo1.Lines.Add('Except');
    end;
    tmp.Free;
    tmp2.Free;
  end;

Мы намерено не создали объект tmp !!! Чтобы посмотреть,  что же будет?

Код выполнится так:
1. Возникнет бага, мы же не создали объект критической секции и не присвоили ее tmp !
2. Попадаем в конструкцию между ключевыми словами  finally и end, там где вывод "Finally1"
3. После этого попадаем в конструкцию между ключевыми словами  except и end, там где вывод "except".

Возникает вопрос, а почему так? А почему не выполнился код, который между ключевыми словами finally и end, там где используется вывод "finally2" ?

А дело вот втом что когда мы используем try-конструкции Delphi инкапсулирует следующую работу:
1) Регистрация обработчика исключительной ситуации, а это часть кода между finally-end и except-end !!!
2) В обработчик передается объект исключения
3) В ситуации применения try-finally-end объект исключения созданный между try и finally не уничтожается, объект исключения передается следующему обработчику. В ситуации же примениния try-except-end объект искючения созданный между try и exсept, гарантированно уничтожается между словами except и end!!!

Из п.3 мы можем заключить, что в try-finally-end мы объект не убивается, потому управление получит код между except и end. Как только раскоментируем строку с созданием объекта tmp, то все будет ок!!!

3. Применение
Раз между finally-end не уничтожается объект исключения, то зачем тогда он нужен ? Хороший вопрос ;)

Дело в том что, код между код finally и end выполнится в любом случае, а код между except и end только когда будет исключение!!!
И в итоге try и finally нужен он для того чтобы , корректно завершить все действия связанные по уничтожению объекта!

Пример:
1. Попытка открыть файл позаписи
2. Попытка записать событие в лог-файл
3. Уничтожить объект

В случае если мы пункты разместим так:
Код

try
// 1.
// 2.
finally
// 3.
end;


то у нас будет корректно закрыт файл! Даже если произошла исключительная ситуация.

Нюанс!!!

А вдруг она произошла в п.1, то выполнится п3, но ведь объект исключения не уничтожается !!! Что будет дальше? А дальше все это дело можно обернуть в конструкцию try-except-end, где между try и except поместить наш код, а в except и end обработать наши ошибки. вот теперь все!

4. Запись от SAP (Петрович)`a:
Код

try try
// пытаемся выполнить
finally end
// уничтожаем объекты
except
// обрабатываем ошибки
end;


Нюанс от SAP (Петрович)`a
Код между finally-end выполнится в любом случае, даже если вызвали Exit! Вот доказательство его слов:
Код

  procedure TfrmMain.Button2Click(Sender: TObject);
  var
    tmp3 : TCriticalSection;
  begin
    tmp3 := Nil;
    try
      try
        tmp3.Acquire;
        Memo1.Lines.Add('First bug');
        tmp3.Release;
      except
        on E: Exception do
        begin
          Memo1.Lines.Add(E.Message);
          Exit;
        end;
      end;
    finally
      Memo1.Lines.Add('Finally-end');
    end;
  end;

Это означает что этот факт можно использовать для завершающих действий.

Автор: MetalFan 30.9.2007, 17:38
Цитата(EvilsInterrupt @  30.9.2007,  12:23 Найти цитируемый пост)
MetalFan, не совсем так, как описал ;)

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

Автор: EvilsInterrupt 30.9.2007, 18:54
Код

ро то, как устроено SEH?

Затем, что вопрошающий - это возможный будущий серьезный программер. И он обязан понимать, что во время возникновения баги, создается объект исключения! Это дает четкое понимание, что в последствии объект обязан быть уничтожен! Я этого поначалу непонимал, потому что это не сразу бросается в глаза.

Автор: MetalFan 30.9.2007, 20:10
Цитата(EvilsInterrupt @  30.9.2007,  18:54 Найти цитируемый пост)
это возможный будущий серьезный программер.

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

Цитата(EvilsInterrupt @  30.9.2007,  18:54 Найти цитируемый пост)
И он обязан понимать, что во время возникновения баги, создается объект исключения! 

для программиста на делфи это совершенно прозрачно... тем более, что никакой прямой работы с SEH в делфи не требуется

Автор: Петрович 1.10.2007, 12:38
Согласен с MetalFan.

Цитата(EvilsInterrupt @  30.9.2007,  19:54 Найти цитируемый пост)
И он обязан понимать, что во время возникновения баги, создается объект исключения! Это дает четкое понимание, что в последствии объект обязан быть уничтожен!

Ну тогда попробуй объяснить в терминах языка Delphi где тут уничтожается объект исключения:
Код

try
// Попытка выполнить
except
// Выполнить обработку ошибки или попытаться исправить ситуацию
end;

smile
И вообще, где тут объект исключения?  Я лично не вижу! Хотя, коечно, как "опытный" программер понимаю что он там неявно существует.
Короче, действительно, не обязательно знать дельфисту что такое объект исключения. А вот как пользоваться try finally/except блоками действительно знать необходимо. Соответственно, если уж объяснять, то объяснять надо именно в терминологии Delphi а не WinAPI.

Автор: bems 1.10.2007, 14:05
Объект исключения не обязательно уничтожается. Например для нехваток памяти используется созданый при старте программы объект, а потом он остается на случай если проблема снова возникнет (т.к. при нехватке памяти создать новый объект может и не получиться).
И вообще вести речь об уничтожении объекта исключения стоит только тогда, когда нарушен естественный ход процесса (например AcquireExceptionObject).
Цитата(Петрович @  1.10.2007,  12:38 Найти цитируемый пост)
Ну тогда попробуй объяснить в терминах языка Delphi где тут уничтожается объект исключения:
внутри пятой строки
Цитата(EvilsInterrupt @  30.9.2007,  12:23 Найти цитируемый пост)
Нюанс от SAP (Петрович)`a
Код между finally-end выполнится в любом случае, даже если вызвали Exit!
Ага. И goto и break и continue и halt. Вот то-то и оно, что конструкция
Код

try
finally
end;
вообще не имеет отношения к исключениям в смысле Дельфи, а предназначена для выполнения секции finally-end при любом выходе из секции try-finally

Добавлено через 3 минуты и 38 секунд
Цитата(EvilsInterrupt @  30.9.2007,  12:23 Найти цитируемый пост)
А вдруг она произошла в п.1, то выполнится п3, но ведь объект исключения не уничтожается !!! 
а вот там его вообще может не быть!!

Автор: EvilsInterrupt 1.10.2007, 19:24
Цитата

Объект исключения не обязательно уничтожается.

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

Цитата

вообще не имеет отношения к исключениям в смысле Дельфи

С каких это пор try-finally-end перстало являться исключением в смысле Delphi ?
Вот выдержка из справки к Delphi 2007 Update 1:
Цитата

Try...finally Statements
Sometimes you want to ensure that specific parts of an operation are completed, whether or not the operation is interrupted by an exception. For example, when a routine acquires control of a resource, it is often important that the resource be released, regardless of whether the routine terminates normally. In these situations, you can use a try...finally statement. 

The following example shows how code that opens and processes a file can ensure that the file is ultimately closed, even if an error occurs during execution. 
Код

Reset(F); 
try 
   ... // process file F 
finally 
   CloseFile(F); 
end;


Автор: bems 3.10.2007, 13:45
Цитата(EvilsInterrupt @  1.10.2007,  19:24 Найти цитируемый пост)
С каких это пор try-finally-end перстало являться исключением в смысле Delphi ?
ну некоторая связь есть, в том смысле что для внешних исключений ибъект исключения создается именно в этой конструкции. Но приведенная тобой цитата говорит только что это можно использовать если предполагаешь исключения. А можно и для других целей.
Цитата(bems @  1.10.2007,  14:05 Найти цитируемый пост)
Ага. И goto и break и continue и halt
тут я преувеличил. только break,  continue и exit. Но все-таки исключений здесь нет, а конструкция работает.

Цитата(EvilsInterrupt @  1.10.2007,  19:24 Найти цитируемый пост)
Прошу привести код, который бы это демонстриовал или хотя бы по косвенным признакам могли бы судить о правильности ваших слов
ну вот же
Цитата(bems @  1.10.2007,  14:05 Найти цитируемый пост)
Например для нехваток памяти используется созданый при старте программы объект, а потом он остается на случай если проблема снова возникнет (т.к. при нехватке памяти создать новый объект может и не получиться).

это в SysUtils
Код

procedure InitExceptions;
begin
  OutOfMemory := EOutOfMemory.CreateRes(@SOutOfMemory);
  InvalidPointer := EInvalidPointer.CreateRes(@SInvalidPointer);
  ErrorProc := ErrorHandler;
тут мы видим создание объектов при инициализации. Потом делается raise уже для существующего объекта. И он не уничтожается до завершения модуля SysUtils

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