Lazarus

Free Pascal => General => Topic started by: pcurtis on April 18, 2021, 08:41:35 am

Title: [SOLVED] To Free or not to Free. That is the question
Post by: pcurtis on April 18, 2021, 08:41:35 am
If I create an object -

MyObject.Create;

Is it better to FreeAndNil(MyObject) or is MyObject.Free enough?

Do I have to free stringlists after I create them?

Thanks in advance.
Title: Re: To Free or not to Free. That is the question
Post by: Thaddy on April 18, 2021, 09:03:47 am
1. FreeAndNil is basically and mostly a stop gap for sloppy programming: Use after Free.. But there are some - but rare - scenario's that warrant it.
Personally, if I have to use FreeAndNil to get a program working, I'd go through the code to find where I was sloppy: FreeAndNil all too often hides bugs. (Algorithmic bugs, that is)
(Now you know that I use it too,, Sometimes..  :-[ )
The cost is negligable, though, except in loops, but note my remark about hiding bugs: e.g. Use after free becomes indetectable...OTOH constructs like if assigned() become more reliable. (As well as object pooling)

2. Yes, you will need to free stringlists. TStringlist is a class so should be free'd.
Title: Re: To Free or not to Free. That is the question
Post by: AlexTP on April 18, 2021, 09:04:59 am
No difference; but FreeAndNil is better sometimes- makes sure that obj becomes Nil and you won't reuse it.
Title: Re: To Free or not to Free. That is the question
Post by: Thaddy on April 18, 2021, 09:13:41 am
No difference; but FreeAndNil is better sometimes- makes sure that obj becomes Nil and you won't reuse it.
Big difference, see my remarks above...
Title: Re: To Free or not to Free. That is the question
Post by: Thaddy on April 18, 2021, 09:41:13 am
A couple of links for further reading:
http://pages.cs.wisc.edu/~rkennedy/freeandnil
https://www.delphitools.info/2010/02/06/dont-abuse-freeandnil-anymore/
https://blogs.embarcadero.com/a-case-when-freeandnil-is-your-enemy/
The latter is recommended, I discussed this - in person - with Allen Bauer, former lead tech scientist for Delphi.
Op.Cit.:
"My point was that using FreeAndNil can sometimes appear to solve the actual problem, when in fact if has merely traded it for another, more insidious, hard to find problem. A problem that doesn’t bite immediately."

And he actually wrote FreeAndNil....A.K.A. NilAndFree.
(Because the global reference is nilled  before the local reference is destroyed)

If you own a Delphi 7 license with RTL sourcecode (professional upwards) you will find that FreeAndNil is declared, but otherwise never used..... Grep -E. It is used in the VCL, though.
I don't know about higher versions, although it seems XE2 is also not using it in the RTL either..
Note: quick Sunday morning check, I may have overlooked something here and there.
Relevant link : https://www.youtube.com/results?search_query=black+cadillac+blues
Title: Re: To Free or not to Free. That is the question
Post by: pcurtis on April 18, 2021, 10:29:12 am
Thanks for the info.
Title: Re: [SOLVED] To Free or not to Free. That is the question
Post by: Thaddy on April 18, 2021, 10:34:37 am
Check the last link I added for what happens if do do not pay attention (posts crossed)
Replace all references to women with FreeAndNil.. Enjoy.
(you will need some knowledge about southern USA slang to appreciate it.)
Title: Re: [SOLVED] To Free or not to Free. That is the question
Post by: ASerge on April 18, 2021, 07:37:21 pm
Thaddy, you've only given references to one point of view. Here (https://blog.eurekalog.com/2009/04/why-should-you-always-use-freeandnil_28.html) is an example for another one.
About the source code. I just did a search for FreeAndNil (whole word) in the Delphi Community sources - 2594 matches!
Title: Re: [SOLVED] To Free or not to Free. That is the question
Post by: Thaddy on April 18, 2021, 08:01:21 pm
Thaddy, you've only given references to one point of view.
Well, Allen Bauer is the author - both the routine and the blog post -. :o I rest my plea.

Sounds like Covid denial..... Facts are not open to opinion, you know that.
Title: Re: [SOLVED] To Free or not to Free. That is the question
Post by: Thaddy on April 18, 2021, 08:07:05 pm
2594 matches!
But NOT in the Delphi RTL sources. Incompetence is not an art.
Of those 2594 hits, maybe, just maybe, 94 are relevant.

BTW I am not accusing you of incompetecance, I highly esteem your skills.
I am merely making a point.
Title: Re: [SOLVED] To Free or not to Free. That is the question
Post by: Thaddy on April 18, 2021, 08:42:27 pm
@ASerge
The link you posted is a solid ground to dismiss the author if I were to employ him. :P :'( >:D
The good thing to learn from this is that a programmer should be a critic of his own code... Allen did...
Title: Re: [SOLVED] To Free or not to Free. That is the question
Post by: ASerge on April 18, 2021, 10:50:04 pm
But NOT in the Delphi RTL sources. Incompetence is not an art.
Of those 2594 hits, maybe, just maybe, 94 are relevant.
I realized that incompetence is just your opinion.
In RTL 103 matches. Compared to Delphi 7 (17 matches) this suggests that defensive coding and trying to avoid problems in large projects is perhaps more important than supposedly sloppy programming.
Title: Re: To Free or not to Free. That is the question
Post by: marcov on April 18, 2021, 11:05:20 pm
1. FreeAndNil is basically and mostly a stop gap for sloppy programming: Use after Free..

I read the "A case against Freeandnil article" article again, and Alan never says anything like that. It says it is not a silver bullet to cover up problems, but he also says:

Quote
FreeAndNil itself isn’t the culprit here.

He seemed to be more ticked off at people at SO telling everybody that a .free is evil and I agree with that. But that doesn't automatically that we should invert this policy and reproduce a bunch of links like Thaddy does on every mention like freeandnil. That is even more destructive.


Jeroen Pluimers seems to care about accidentally passing interface references to it, and the general untypedness  (https://wiert.me/2017/12/21/another-case-against-freeandnil/)

True, but IMHO a very minor point.

Eric Grange wants to introduce a TObject(1) magic constant (https://www.delphitools.info/2010/02/06/dont-abuse-freeandnil-anymore/) to avoid things. He refers to other links to list the problems however, and doesn't reiterate them.

In short, so while in odd cases, freeandnil can obscure, there is a lot of loose sand here, and there doesn't seem to be coherent direction.

I myself rely on freeandnil (and thus on checking if a reference has been freed) a lot during shutdown, when it is a protective layer to avoid generating a cascade of exceptions if something goes wrong in the various parts of the program (gui including opengl, mainprogram logic. Threads that might or might not interface hardware etc) and preferably get some reasonable copy of the program's state to disk.

Title: Re: To Free or not to Free. That is the question
Post by: Remy Lebeau on April 19, 2021, 06:50:28 pm
FreeAndNil is basically and mostly a stop gap for sloppy programming: Use after Free.. But there are some - but rare - scenario's that warrant it.

On a similar token, one might argue that even Free() can be seen as another helper that promotes sloppy programming.

The actual class destructor is Destroy(), not Free().  The only difference between them is that Free() checks for nil before then calling Destroy().  But most of the time, in code that manages its pointers correctly, a pointer will not be nil when Free() is called on it, eg:

Code: Pascal  [Select][+][-]
  1. SL := TStringList.Create;
  2. try
  3.   ...
  4. finally
  5.   SL.Free; // <-- SL is not nil here!
  6. end;

Which is essentially doing this:

Code: Pascal  [Select][+][-]
  1. SL := TStringList.Create;
  2. try
  3.   ...
  4. finally
  5.   if SL <> nil then SL.Destroy; // <-- nil check is redundant!
  6. end;

The primary reason that Free() even exists at all is to handle the case where a class' constructor raises an exception (and if you have a constructor that is raising exceptions, you likely have more important issues to worry about).  Its destructor still gets called, and needs to free any object members that were already constructed prior to the exception being raised, eg:

Code: Pascal  [Select][+][-]
  1. constructor TMyClass.Create;
  2. begin
  3.   inherited;
  4.   Member1 := TSomeClass.Create;
  5.   DoSomethingThatMayRaise;
  6.   Member2 := TAnotherClass.Create;
  7. end;
  8.  
  9. destructor TMyClass.Destroy;
  10. begin
  11.   if Member1 <> nil then Member1.Destroy; // <-- may be nil or non-nil
  12.   if Member2 <> nil then Member2.Destroy; // <-- may be nil or non-nil
  13.   inherited;
  14. end;

By exposing Free() as a wrapper for Destroy(), it makes writing a destructor a little easier so it doesn't have to know whether the constructor was successful or not, since all class members are zero'ed/nil'ed before the constructor is called.

Code: Pascal  [Select][+][-]
  1. constructor TMyClass.Create;
  2. begin
  3.   inherited;
  4.   Member1 := TSomeClass.Create;
  5.   DoSomethingThatMayRaise;
  6.   Member2 := TAnotherClass.Create;
  7. end;
  8.  
  9. destructor TMyClass.Destroy;
  10. begin
  11.   Member1.Free;
  12.   Member2.Free;
  13.   inherited;
  14. end;

So, it could be argued that Free() should only be called on a pointer that has the possibility of being nil when its object needs to be destroyed, otherwise Destroy() should be called directly.

But, the cost of calling Free() instead of Destroy() directly is usually negligable...
Title: Re: To Free or not to Free. That is the question
Post by: 440bx on April 19, 2021, 08:20:31 pm
FreeAndNil is basically and mostly a stop gap for sloppy programming: Use after Free.. But there are some - but rare - scenario's that warrant it.

On a similar token, one might argue that even Free() can be seen as another helper that promotes sloppy programming.

The actual class destructor is Destroy(), not Free().  The only difference between them is that Free() checks for nil before then calling Destroy().  But most of the time, in code that manages its pointers correctly, a pointer will not be nil when Free() is called on it
I have to say that "features" that _hide_ bugs in program are not "desirable" features.  I think the programmer would be better off getting an access violation which would hopefully cause him/her to fix the error.
Title: Re: To Free or not to Free. That is the question
Post by: ASerge on April 20, 2021, 01:30:00 am
I think the programmer would be better off getting an access violation which would hopefully cause him/her to fix the error.
FreeAndNil brings it closer. Without zeroing, the error can be hidden for a long time.
Title: Re: To Free or not to Free. That is the question
Post by: 440bx on April 20, 2021, 01:49:39 am
I think the programmer would be better off getting an access violation which would hopefully cause him/her to fix the error.
FreeAndNil brings it closer. Without zeroing, the error can be hidden for a long time.
I basically agree with what you stated above.  What I find sloppy is that when a class is Destroy()-ed, the pointer (apparently) isn't set to nil, nor when it is simply freed.  It has to be FreeAndNil. 

It seems to me that, there should be one way to "release" a class that takes care of everything that needs to be taken care of when it is released/freed, not three (3) different ways that all seem to have, at least, some holes in them.
Title: Re: To Free or not to Free. That is the question
Post by: PascalDragon on April 20, 2021, 09:17:28 am
I think the programmer would be better off getting an access violation which would hopefully cause him/her to fix the error.
FreeAndNil brings it closer. Without zeroing, the error can be hidden for a long time.

This only helps for the reference passed to FreeAndNil. If you copied the reference to other classes then those won't be set to Nil once FreeAndNil is called on the original.
Title: Re: [SOLVED] To Free or not to Free. That is the question
Post by: Thaddy on April 20, 2021, 09:27:08 am
That is my whole point expressed more eloquently.
Title: Re: [SOLVED] To Free or not to Free. That is the question
Post by: jcmontherock on April 20, 2021, 11:03:08 am
I have a more generally question: Do we have to Free or FreeAndNil every global Object we have created in the app before
closing it ?
Title: Re: [SOLVED] To Free or not to Free. That is the question
Post by: PascalDragon on April 20, 2021, 04:39:44 pm
I have a more generally question: Do we have to Free or FreeAndNil every global Object we have created in the app before
closing it ?

If it isn't freed through some other means (e.g. part of a TObjectList with OwnsObjects set to True, a TComponent-descendant with a Owner set or an object instance which is used only with interfaces) then yes, you need to free each and every object.
Title: Re: [SOLVED] To Free or not to Free. That is the question
Post by: pcurtis on April 20, 2021, 04:56:34 pm
I think he means is it enough just to Free or is it better to FreeAndNil?
Title: Re: [SOLVED] To Free or not to Free. That is the question
Post by: howardpc on April 20, 2021, 06:55:40 pm
Free is sufficient.
The app is closing.
The OS will manage and reallocate the memory it allocated to the app from that point on. The app is dead and gone.
Title: Re: [SOLVED] To Free or not to Free. That is the question
Post by: ASerge on April 20, 2021, 07:07:11 pm
I think he means is it enough just to Free or is it better to FreeAndNil?
For local (not used twice) variable, or used only inside class/unit (rarely) - Free is sufficient.
For a global variable (typed constants), public fields (or are the basis for public properties) - FreeAndNil.
If you mix interfaces and classes - always use FreeAndNil.
Fortunately, in FPC, the FreeAndNil procedure is not inlined, which makes it a little more efficient (there is no code bloat, as in Delphi).

By the way, for some reason, ReallocMem(P, 0) is rarely used. Instead, it is often written FreeMem(P); P := nil. Although the first is more effective and safer (check for nil).
TinyPortal © 2005-2018