Alex Rivera | Logout

Delphi Exception Handling - How to clean up properly?

Asked 2010-03-18T21:51:35.003
10

I'm looking at some code in an application of ours and came across something a little odd from what I normally do. With exception handling and cleanup, we (as well as many other programmers out there, I'm sure) use a Try/Finally block embedded with a Try/Except block. Now I'm used to the Try/Except inside the Try/Finally like so:

Try
  Try
    CouldCauseError(X);
  Except
    HandleError;
  end;
Finally
  FreeAndNil(x);
end;

but this other block of code is reversed as so:

Try
  Try
    CouldCauseError(X);
  Finally
    FreeAndNil(x);
  end;
Except
  HandleError;
end;

Looking around the web, I'm seeing folks doing this both ways, with no explanation as to why. My question is, does it matter which gets the outside block and which gets the inside block? Or will the except and finally sections get handled no matter which way it is structured? Thanks.

Edit
Report

1 Answer

0

At first your code looks a little bit strange. I miss the creation of X.

X := CreateAnX
try
  DoSomeThing(X);
finally
  FreeAndNil(x);
end;

It is important. Because if you have code like this

// don't do something like this
try
  X := CreateAnX
  DoSomeThing(X);
finally
  FreeAndNil(x);
end;

you can be lucky and it works. But if the construction fails you can be "lucky" and get an access violation or you have bad luck and get an access violation some times later at an completely different code position.

An alternative could be

X := nil;
try
  X := CreateAnX
  DoSomeThing(X);
finally
  FreeAndNil(x);
end;

Where to use except depends on what is your intention. When you want to catch every exception and know all calling code clean its problems (using try finally) then an outer except-block is the way to go

try
  X := CreateAnX
  try
    DoSomeThing(X);
  finally
    FreeAndNil(x);
  end;
except
  on e: Exception do
    LogException(e)
end;      

But always think about it when you want catch all errors. As an example (and I often see it wrong) don't do it in an Indy OnExecute-handler this way. There you must use something like this

try
  X := CreateAnX
  try
    DoSomeThing(X);
  finally
    FreeAndNil(x);
  end;
except
  on EIdException do
    raise;
  on e: Exception do
    LogException(e)
end;      

If you expect an exception because you throw it or (as an example) a conversation can fail, look for the most inner position to catch the error:

X := CreateAnX
try
  DoSomeThing(X);
  try
    i := StrToInt(X.Text);
  except
    on EConvertError do
      i := 0;
  end;       
finally
  FreeAndNil(x);
end;

don't do it this way

X := CreateAnX
try
  try
    DoSomeThing(X);
    i := StrToInt(X.Text);
 
answered 2010-03-19T09:24:39.137

Your Answer