In Delphi 5, Free Free may throw an exception?

In Delphi 5, I wrote code that calls Free for several variables in a finally block, for example

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

This code assumes that Free never go up, because if, for example, a.Free raised, then there would be a memory leak for b and c . Is this assumption justified?

+6
source share
5 answers

The Free method itself does not explicitly throw an exception, but it calls a Destroy virtual destructor, which can certainly throw an exception.

So, if you want to be sure that all your objects are destroyed, even if one of the destructors throws an exception, you will get the following code:

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

Having said that, there should be a design principle that you make no exceptions in the destructor. So, in my opinion, it is completely reasonable to assume that if an exception occurs in the destructor, then your program is largely closed. Leakage of objects at this moment is nothing to worry about. If your destructor throws an exception, you are probably already leaking because this destructor has not completed.

So, in my opinion, it is quite reasonable to combine some calls on Free and, of course, you avoid deeply nested try / finally , which is worth striving for.

If you want only one try / finally , then remember to write the code as follows:

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

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

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

I gave my FreeAndNil the same name as the function in SysUtils , which at first glance may seem strange, but it is safe and friendly. Naturally, these helpers come to their senses when you have more than two objects.

+10
source

Depends on what happens in the destructor.

+3
source

There can be two things that SomeObj.Free can SomeObj.Free to SomeObj.Free an exception:

  • An SomeObj exception in the destructor of an instance of SomeObj class or its ancestors.
  • Invalid class reference due to uninitialized SomeObj variable.

In your case, if a.Free throws an exception for any of the above reasons, a memory leak has occurred for object b and c and possibly some leak inside object a due to an unhandled exception in the destructor.

+2
source

if your a.free throws an exception, a (depending on how much the destructor has freed itself from the fields of the object), objects b and c will leak out because execution will be aborted. Anyway, something is wrong in your destructor if it causes an error. therefore, you must protect the code with try..finally blocks, but IMHO you must make sure that destructors do not give you any error circumstances.

+1
source

Of course, FREE can throw exceptions - so yes, you will leak memory into your code, if A.FREE throws an exception, B.FREE and C.FREE will not be called.

The question is, do you want to handle exceptions or let them happen? It will depend on what your code will be for, other developers will use it (for example). To prevent memory leaks, you should insert try..finally sections;

 a:=tobject.create; try b:=tobject.create; try c:=tobject.create; ... finally c.free; end; finally b.free; end; a.free; 

The kind of thing. Its a question of what your code really does if you should also wrap A.FREE in the try..finally section, although I assume that you probably should.

0
source

Source: https://habr.com/ru/post/907920/


All Articles