Finally ブロックの記述
保護ブロックの定義 への移動
例外ハンドラは、保護されているコード ブロック内で発生する特定の例外(複数の場合あり)を処理するコードです。 一方、たとえ例外が発生しても、例外を処理する必要はないものの、保護ブロックの後に実行したいコードがある場合もあります。 通常、そのようなコードでは、保護ブロックの前に割り当てられたリソースの解放など、クリーンアップの問題を処理します。
アプリケーションでリソースを割り当てる場合、finally ブロックを使用することで、たとえ例外が発生してもそのリソースを確実に解放することができます。 したがって、アプリケーションでメモリを割り当てる場合は、このメモリが最終的に必ず解放されるようにすることができます。 アプリケーションでファイルを開く場合は、後でそのファイルを確実に閉じることができます。 普通の状況では、割り当てと解放の両方のコードをアプリケーションに含めることで、アプリケーションで割り当てたリソースを確実に解放できます。 しかし、例外が発生する場合でも、リソースを解放するコードがアプリケーションで必ず実行されるようにする必要があります。
必ず解放しなければならないリソースとしては、一般に以下のものがあります。
- ファイル
- メモリ
- Windows リソースまたはウィジェット ライブラリ リソース(Qt オブジェクト)
- オブジェクト(アプリケーション内のクラスのインスタンス)
次のイベント ハンドラでは、割り当てたメモリを例外のためアプリケーションで解放できなくなる例を示しています。
procedure TForm1.Button1Click(Sender: TObject);
var
APointer: Pointer;
AnInteger, ADividend: Integer;
begin
ADividend := 0;
GetMem(APointer, 1024);{ allocate 1K of memory }
AnInteger := 10 div ADividend;{ this generates an exception }
FreeMem(APointer, 1024);{ this never gets called because of the exception}
end;
ほとんどのエラーはこれほど明白ではありませんが、この例は重要な点を明らかにしています。つまり、 例外が発生すると、実行はブロック外にジャンプするので、メモリを解放する文は決して呼び出されないということです。
メモリを確実に解放するには、try ブロックを finally ブロックと一緒に使用することができます。
'finally' ブロックを書く
finally ブロックは finally キーワードで始まります。 このブロックは try..finally 文の一部であり、次のような形式になっています。
try { statements that may raise an exception} finally { statements that are called even if there is an exception in the try block} end;
try..finally 文では、たとえ try ブロックで例外が発生しても、アプリケーションは finally 部の文を必ず実行します。 try ブロック内のコード(または try ブロック内のコードで呼び出されたルーチン)で例外が発生した場合、実行はそこで停止します。 例外ハンドラが見つかったら、実行は finally 部(クリーンアップ コードと呼ばれます)にジャンプします。 finally 部が実行された後、その例外ハンドラが呼び出されます。 例外が発生しない場合、クリーンアップ コードは通常の順序で実行されます。つまり、try ブロックにあるすべての文の後で実行されます。
メモリを割り当てた後でエラーが発生した場合にも割り当てたメモリが解放されるように finally ブロックを使用しているイベント ハンドラの例を次のコードで示します。
procedure TForm1.Button1Click(Sender: TObject); var APointer: Pointer; AnInteger, ADividend: Integer; begin ADividend := 0; GetMem(APointer, 1024);{ allocate 1K of memory } try AnInteger := 10 div ADividend;{ this generates an exception } finally FreeMem(APointer, 1024);{ execution resumes here, despite the exception } end; end;
finally ブロック内の文は、例外の発生に関係なく実行されます。 try 部の文で例外が発生しない場合は、finally ブロックが引き続き実行されます。