The Delphi language shares with many others a standard resource allocation pattern to make sure that in case of an exception the resources is properly released. Resources in this context are memory objects, files, operating system objects and handles, and the like. In Delphi, compared to other languages with a garbage collector, the relevance increased by memory management considerations.

Protecting a Single Object

In the most simple cases, you'd write code like:

allocate resource try use resource finally free resource end;

A more specific example would be like:

A1 := TTest.Create; try A1.DoSomething; finally A1.Free; end;

So far, so good. Notice that is an error happen during the constructor execution, Delphi will automatically execute the destructor for the partially initialized object (but this could be a topic for another blog post).

Protecting Two Objects: How NOT to Write the Code

The issue I want to focus on is how to write the same type of code if you need to allocate and dispose two resources. Here there are multiple options. What you shouldn't do (but is fairly common) is to write:

A1 := TTest.Create; A2 := TTest.Create; try A1.DoSomething; A2.DoSomething (A1); finally A2.Free; A1.Free; end;

The issue with this code is that in case the creation of A2 fails (and there could be many reasons), the A1 object would remain in memory. Simply pushing the second allocation within the try block is also not good:

A1 := TTest.Create; try A2 := TTest.Create; A1.DoSomething; A2.DoSomething (a); finally A2.Free; A1.Free; end;

With this code in case of a failure in object A2 constructor call, the finally block will try to Free an uninitialized object (the default value of a local object reference is undefined). This is why a possible solution is to set A2 to nil at the beginning -- as calling Free on a nil object has no effect. Or set all object reference to nil for simplicity and uniformity. Or write two nested try blocks to protect each of the resources.

Protecting Two Objects: A Tale of Three Solutions

This long introduction brings us to the point of this blog post. There are at least 3 different correct solution for the issue of protecting two resources in the same code block, as I just mentioned. Here are the three solutions in an image I "borrowed" from one of our RAD Studio R&D architects, Bruneau Babet.

Provided they are all correct in terms of proper resource management in all scenarios, which are the advantages and disadvantages of these 3 solutions? What is important to consider is that the 2 resources could be 3, or 4 or half a dozen. 

Which One to Pick?

The first solution with the nested try blocks fairly clean but more verbose (more lines of code) and has additional nesting that could become an annoyance with multiple resources. Also, there is a runtime cost associated with try blocks, clearly limited but not zero. 

The second solution has the least amount of lines of code code and the least amount of runtime cost. The only additional is setting A2 to nil. The code remains readable also with many resources. However, the code is "unbalanced" and it might be slightly confusing.

The third solution goes in the same direction, but it adds one extra technically useless assignment to nil (for A1), offering the advantage of being cleaner and more balanced, and likely more readable after all.

So what's the best solution? This is really hard to tell,. I personally mostly used #1 in my books, but at Embarcadero we tend to prefer the cleaner and faster ones (that is, #2 or #3) for library code. Interested in your opinions, of course.

Anonymous
  • [url=https://www.google.com]Google[/url] Which One WOrks here
  • I somehow missed to make it clear that I mean exceptional also when an exception is raised by a bug in a destructor (code called from destructor) written by a (perhaps junior :-) ) colleague, perhaps one that is hard to reproduce (and for this reason, also hard to fix). This is a fact of life and it's just not enough to say to developers to not write buggy code. Also take legacy code into consideration (say, 20 years old), the fix of which might affect many other parts of the application, might be hard to test and therefore might be risky. Scheduling and deploying the bugfix might be subject of multiple factors and out of the individual developer's control. Until then we should try our best to protect remaining resources and program operability as long as it is possible or required. That's another question again that after such a bug whether we should terminate the program immediately or continue without further notice or suggest the user to save changes and restart the application or... (and what about background services, etc...) and the selected strategy is also not always the decision of an individual developer and might depend on multiple factors... Developer life is full of bugs and hostile code...
  • So, using my procedures I can do #3 as var A1, A2: TTest; begin Set_Objects_To_Nil( A1, A2 ); try A1 := TTest.Create; A2 := TTest.Create; // Use A1 and A2 finally FreeObjects( A1, A2 ); end; end;
  • :) Like I said, no advantages in readability or verbosity. This would probably look better if anonymous methods in Delphi could be declared some other way, with less verbosity.
  • Yes, than is indeed the main goal!
  • Yes, thank you. It's nice solution when just one object is necessary.
  • It is not reqiured to declare variable just two anonymous procedures :) Too much utility code.
  • I have found some Delphi programmers use Destroy instead of Free. This will of course create problems freeing a nil object. Of course one has to wonder why they are doing that in the first place. I can't think of any good reason to use Destroy directly.
  • The Using class will allow you to replace the #1 solution, like so: // Multiple resource protection #1 Using.New( procedure (A1: TTest) begin Using.New( procedure (A2: TTest) begin A1.DoSomething; A2.DoSomething; end ); end ); Of course, one can argue "what's the point?". There is no real advantage in readability, nor in verbosity. I found this method has, nonetheless, two advantages: * It's impossible to forget freeing your object at the right place * It is not required to declare a variable for the object, as one is provided by the Using class itself The Using class also creates the object itself, if the constructor requires no params, but if it does, you are allowed to provide your own constructor call, like so: // Using class with custom constructor Using.New( TTest.Create('Param'), procedure (A: TTest) begin A.DoSomething; end );
  • The Using class is basically an anonymous method wrapped inside a try...finally block. :)
  • var A1, A2: TTest; P1, P2: TProc; begin P2 := procedure (A2: TTest) begin A1.DoSomething; A2.DoSomething; end; P1 := procedure(A1: TTest) begin Using.New(P2); end; Using.New(P1); end;
  • How the Using class does help you to free non interfaced objects without try-finally section?
  • The webpage seems to have swallowed the not-equals between Self and nil.
  • Yes, i was wrong. Don´t see the initialization at start in nil value.
  • Free is implemented as "if Self nil then Destroy". So, checking if A1 is assigned is redundant.