Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In Delphi 5, can Free ever raise an exception?

In Delphi 5, I've currently written code that calls Free on multiple variables in a finally block, e.g.

...
finally
    a.Free;
    b.Free;
    c.Free;
end;

This code assumes that Free can never raise, since if, for example, a.Free raised, the memory for b and c would be leaked. Is this assumption justified?

like image 739
Stuart Golodetz Avatar asked Feb 08 '12 10:02

Stuart Golodetz


3 Answers

The Free method itself does not explicitly raise an exception, but it calls the virtual destructor Destroy which certainly could raise an exception.

So if you want to be sure that all your objects are destroyed, even if one of the destructors raises an exception you end up with code like this:

a := TMyObject.Create;
try
  b := TMyObject.Create;
  try
    ...
  finally
    b.Free;
  end;
finally
  a.Free;
end;

Having said that, it should be a design principle that you do not raise exceptions in a destructor. So, in my view it's perfectly reasonable to take the viewpoint that if an exception is raised in destructor, then your program is pretty much hosed. Leaking objects at that point is not something to worry about. If your destructor has raised an exception then you are probably already leaking because that destructor did not run to completion.

So in my view it can be perfectly reasonable to group together some calls to Free and of course you avoid deeply nested try/finally which is something worth striving for.

If you want just one try/finally then remember to write the code like this:

a := nil;
b := nil;
try
  a := TMyObject.Create;
  b := TMyObject.Create;
  ...
finally
  b.Free;
  a.Free;
end;

In my own code base I have some helper methods that make this cleaner. Then the code can look like this:

InitialiseNil(a, b);
try
  a := TMyObject.Create;
  b := TMyObject.Create;
  ...
finally
  FreeAndNil(b, a);
end;

I have given my FreeAndNil the same name as the function in SysUtils which on first glance may seem odd, but it is safe and benign to do so. Naturally these helpers come into their own when you have even more than two objects.

like image 97
David Heffernan Avatar answered Oct 08 '22 10:10

David Heffernan


Depends on what's happening in the destructor.

like image 35
Ondrej Kelle Avatar answered Oct 08 '22 10:10

Ondrej Kelle


There could be 2 things that can cause SomeObj.Free to raise an exception:

  1. Unhandled exception in destructor of the SomeObj instance of class or on of its ancestors.
  2. Invalid class reference due to uninitialized variable SomeObj.

In your case if a.Free raises an exception for any of the above reasons, there would be a memory leak for object b and c and maybe some leak inside object a because of unhandled exception in destructor.

like image 33
Vahid Nasehi Avatar answered Oct 08 '22 11:10

Vahid Nasehi