Don‘t try and try again!

The try-finally block is awesome. Especially for creating and freeing objects. But what do you all do when you want to create multiple objects in a row? Create a nested try-finally for ever object you create?

Object1 := TObject.Create;
try
  Object2 := TObject.Create;
  try
    ...
  finally
    FreeAndNil(Object2);
  end;
finally
  FreeAndNil(Object1);
end;

This is obviously quite an overhead when having multiple objects. So let’s create every object at the beginning and free all in the finally-block, right? Hypothetically asking for if it is right should already give you the hint that this is obviously wrong or rather even more bad.
For understanding purposes have an example:

Object1 := TObject.Create;
Object2 := TObject.Create;
try
  ...
finally
  FreeAndNil(Object2);
  FreeAndNil(Object1);
end;

At first this looks like a good idea. We have only one try-finally for as many objects we want to create, but here hides a possible memory leak.
Consider this; the first object got created successfully, but the second one raised an exception while creating. At this point we still are outside the try-finally-statement so we aren’t going to free the object that was previously successfully created.
Have this kind of bug a dozen times and you can say goodbye to your memory or even to your application because the memory ran out for it.

So lets just move the creation of the objects inside the try-finally! Well, that idea would be even more bad.
Variables aren’t initialized so we can assume that the objects point to some garbage. Now one of the objects can’t be created and an exception is raised, but the finally-block gets executed. That’s what we want! But then suddenly we get an access violation because of an object pointing to garbage…

And here comes the final necessary part for creating multiple objects with one try-finally. We just initialize it as nil, because the .Free method checks if the object is <> nil so we can execute this without worrying about errors.

Object1 := nil;
Object2 := nil;
try
  Object1 := TObject.Create;
  Object2 := TObject.Create;
  ...
finally
  FreeAndNil(Object2);
  FreeAndNil(Object1);
end;

With this method of writing one try-finally-statement for multiple objects you can have less overhead, because of no more nested try-finally-statements, and have a better overview of your objects.

Hint: Free the objects at reversed order to minimize bugs because of dependencies between the objects.

TL;DR

Use one try-finally for multiple objects by initializing every object with nil and creating them within the try-block.

Leave a Reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.