Embarcadero Delphi
Использование try, кроме, и, наконец,
Поиск…
Синтаксис
Try-except: try [statements] кроме [[[на E: ExceptionType do statement]] [else statement] | [заявления];
Try-finally: попробуйте [statements] finally [statements] end;
Простой пример. Наконец, чтобы избежать утечек памяти
Используйте try
- finally
чтобы избежать утечки ресурсов (например, памяти) в случае возникновения исключения во время выполнения.
Следующая процедура сохраняет строку в файле и предотвращает утечку TStringList
.
procedure SaveStringToFile(const aFilename: TFilename; const aString: string);
var
SL: TStringList;
begin
SL := TStringList.Create; // call outside the try
try
SL.Text := aString;
SL.SaveToFile(aFilename);
finally
SL.Free // will be called no matter what happens above
end;
end;
Независимо от того, возникает ли исключение при сохранении файла, SL
будет освобожден. Любое исключение отправляется вызывающему абоненту.
Исключительно безопасный возврат нового объекта
Когда функция возвращает объект (вместо того, чтобы использовать тот, который был передан вызывающим), будьте осторожны, исключение не вызывает утечку объекта.
function MakeStrings: TStrings;
begin
// Create a new object before entering the try-block.
Result := TStringList.Create;
try
// Execute code that uses the new object and prepares it for the caller.
Result.Add('One');
MightThrow;
except
// If execution reaches this point, then an exception has occurred. We cannot
// know how to handle all possible exceptions, so we merely clean up the resources
// allocated by this function and then re-raise the exception so the caller can
// choose what to do with it.
Result.Free;
raise;
end;
// If execution reaches this point, then no exception has occurred, so the
// function will return Result normally.
end;
Наивные программисты могут попытаться поймать все типы исключений и вернуть nil
от такой функции, но это всего лишь частный случай общей непривлекательной практики ловли всех типов исключений без их обработки.
Try-finally, вложенный внутри try-except
Блок try
finally
может быть вложен внутри блока try
except
.
try
AcquireResources;
try
UseResource;
finally
ReleaseResource;
end;
except
on E: EResourceUsageError do begin
HandleResourceErrors;
end;
end;
Если в UseResource
возникает UseResource
, выполнение переходит к ReleaseResource
. Если исключением является EResourceUsageError
, то выполнение перейдет к обработчику исключений и вызовет HandleResourceErrors
. Исключения любого другого типа пропустят обработчик исключений выше и перейдут к следующей try
- except
блокировки стека вызовов.
Исключения в AcquireResource
или ReleaseResource
заставят выполнение перейти к обработчику исключений, пропуская блок finally
, либо потому, что соответствующий блок try
еще не введен, либо потому, что блок finally
уже введен.
Попробовать - кроме вложенного внутри try-finally
Блок try
except
может быть вложен в блок try
finally
.
AcquireResource;
try
UseResource1;
try
UseResource2;
except
on E: EResourceUsageError do begin
HandleResourceErrors;
end;
end;
UseResource3;
finally
ReleaseResource;
end;
Если в EResourceUsageError
появляется UseResource2
, то выполнение перейдет к обработчику исключений и вызовет HandleResourceError
. Исключение будет считаться обработанным, поэтому выполнение продолжит UseResource3
, а затем ReleaseResource
.
Если в UseResource2
возникает исключение любого другого типа, то обработчик исключений здесь не будет применяться, поэтому выполнение перепрыгнет через вызов UseResource3
и перейдет непосредственно к блоку finally
, где будет вызываться ReleaseResource
. После этого выполнение перейдет к следующему применимому обработчику исключений, поскольку исключение пузырится вверх по стеке вызовов.
Если исключение возникает в любом другом вызове в приведенном выше примере, тогда HandleResourceErrors
не будет вызываться. Это связано с тем, что ни один из других вызовов не возникает внутри блока try
соответствующего этому обработчику исключений.
Попробуйте, наконец, с двумя или более объектами
Object1 := nil;
Object2 := nil;
try
Object1 := TMyObject.Create;
Object2 := TMyObject.Create;
finally
Object1.Free;
Object2.Free;
end;
Если вы не инициализируете объекты с помощью nil
вне блока try-finally
, если один из них не может быть создан, AV будет происходить в блоке finally, потому что объект не будет равен nil (поскольку он не был инициализирован) и приведет к исключению.
Метод Free
проверяет, равен ли объект нулю, поэтому инициализация обоих объектов с помощью nil
позволяет избежать ошибок при их освобождении, если они не были созданы.