Embarcadero Delphi
try、except、およびfinallyの使用
サーチ…
構文
try-except:[[[E:ExceptionType doステートメントで]] [else文]以外の[statements]を試してください。 [ステートメント]終了;
試してみてください:try [statements] finally [statements] end;
メモリリークを避けるための単純なtry..finallyの例
実行中に例外が発生した場合にリソース(メモリなど)が漏れないようfinally
、 try
- finally
を使用してtry
。
以下の手順では、文字列をファイルに保存し、 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
AcquireResources;
try
UseResource;
finally
ReleaseResource;
end;
except
on E: EResourceUsageError do begin
HandleResourceErrors;
end;
end;
UseResource
内で例外が発生すると、実行はReleaseResource
ジャンプします。例外がEResourceUsageError
場合、実行は例外ハンドラにジャンプし、 HandleResourceErrors
を呼び出しHandleResourceErrors
。他の型の例外は上記の例外ハンドラをスキップし、次のtry
バブルアップします - 呼び出しスタックexcept
ブロックするexcept
ます。
例外AcquireResource
またはReleaseResource
実行をスキップして、例外ハンドラに行くことになります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
で他の型の例外が発生したUseResource2
、ここに表示される例外ハンドラは適用されません。したがって、実行はUseResource3
呼び出しをUseResource3
、 ReleaseResource
が呼び出されるfinally
ブロックに直接移動します。その後、例外がコールスタックをバブルアップするので、実行は次の適用可能な例外ハンドラにジャンプします。
上の例で他の呼び出しで例外が発生した場合、 HandleResourceErrors
は呼び出されません。これは、その例外ハンドラに対応するtry
ブロック内で他の呼び出しが発生しないためです。
2つ以上のオブジェクトを試してみてください
Object1 := nil;
Object2 := nil;
try
Object1 := TMyObject.Create;
Object2 := TMyObject.Create;
finally
Object1.Free;
Object2.Free;
end;
try-finally
ブロックの外側でnil
てオブジェクトを初期化しないtry-finally
、そのうちの1つが作成されなかった場合、AVはfinallyブロックで発生します。なぜなら、オブジェクトは(初期化されていないので)例外が発生します。
Free
メソッドは、オブジェクトがnilであるかどうかをチェックするので、両方のオブジェクトをnil
初期化すると、作成されていなければ解放する際にエラーが回避されます。