[SOLVED] To Free or not to Free. That is the question lazarus / 62-General ---------------------------------------------------------------------- pcurtis · 2021-04-18 06:41 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. ---------------------------------------------------------------------- Thaddy · 2021-04-18 07:03 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. ---------------------------------------------------------------------- AlexTP · 2021-04-18 07:04 No difference; but FreeAndNil is better sometimes- makes sure that obj becomes Nil and you won't reuse it. ---------------------------------------------------------------------- Thaddy · 2021-04-18 07:13 Quote from: Alextp on April 18, 2021, 09:04:59 amNo difference; but FreeAndNil is better sometimes- makes sure that obj becomes Nil and you won't reuse it. Big difference, see my remarks above... ---------------------------------------------------------------------- Thaddy · 2021-04-18 07:41 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 ---------------------------------------------------------------------- pcurtis · 2021-04-18 08:29 Thanks for the info. ---------------------------------------------------------------------- Thaddy · 2021-04-18 08:34 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.) ---------------------------------------------------------------------- ASerge · 2021-04-18 17:37 Thaddy, you've only given references to one point of view. Here 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! ---------------------------------------------------------------------- Thaddy · 2021-04-18 18:01 Quote from: ASerge on April 18, 2021, 07:37:21 pmThaddy, you've only given references to one point of view. Well, Allen Bauer is the author - both the routine and the blog post -. I rest my plea. Sounds like Covid denial..... Facts are not open to opinion, you know that. ---------------------------------------------------------------------- Thaddy · 2021-04-18 18:07 Quote from: ASerge on April 18, 2021, 07:37:21 pm2594 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. ---------------------------------------------------------------------- Thaddy · 2021-04-18 18:42 @ASerge The link you posted is a solid ground to dismiss the author if I were to employ him. The good thing to learn from this is that a programmer should be a critic of his own code... Allen did... ---------------------------------------------------------------------- ASerge · 2021-04-18 20:50 Quote from: Thaddy on April 18, 2021, 08:07:05 pmBut 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. ---------------------------------------------------------------------- marcov · 2021-04-18 21:05 Quote from: Thaddy on April 18, 2021, 09:03:47 am1. 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: QuoteFreeAndNil 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 True, but IMHO a very minor point. Eric Grange wants to introduce a TObject(1) magic constant 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. ---------------------------------------------------------------------- Remy Lebeau · 2021-04-19 16:50 Quote from: Thaddy on April 18, 2021, 09:03:47 amFreeAndNil 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][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i SL := TStringList.Create;try  ...finally  SL.Free; // <-- SL is not nil here!end; Which is essentially doing this: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i SL := TStringList.Create;try  ...finally  if SL <> nil then SL.Destroy; // <-- nil check is redundant!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][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i constructor TMyClass.Create;begin  inherited;  Member1 := TSomeClass.Create;  DoSomethingThatMayRaise;  Member2 := TAnotherClass.Create;end; destructor TMyClass.Destroy;begin  if Member1 <> nil then Member1.Destroy; // <-- may be nil or non-nil  if Member2 <> nil then Member2.Destroy; // <-- may be nil or non-nil  inherited;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][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i constructor TMyClass.Create;begin  inherited;  Member1 := TSomeClass.Create;  DoSomethingThatMayRaise;  Member2 := TAnotherClass.Create;end; destructor TMyClass.Destroy;begin  Member1.Free;  Member2.Free;  inherited;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... ---------------------------------------------------------------------- 440bx · 2021-04-19 18:20 Quote from: Remy Lebeau on April 19, 2021, 06:50:28 pmQuote from: Thaddy on April 18, 2021, 09:03:47 amFreeAndNil 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. ---------------------------------------------------------------------- ASerge · 2021-04-19 23:30 Quote from: 440bx on April 19, 2021, 08:20:31 pmI 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. ---------------------------------------------------------------------- 440bx · 2021-04-19 23:49 Quote from: ASerge on April 20, 2021, 01:30:00 amQuote from: 440bx on April 19, 2021, 08:20:31 pmI 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. ---------------------------------------------------------------------- PascalDragon · 2021-04-20 07:17 Quote from: ASerge on April 20, 2021, 01:30:00 amQuote from: 440bx on April 19, 2021, 08:20:31 pmI 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. ---------------------------------------------------------------------- Thaddy · 2021-04-20 07:27 That is my whole point expressed more eloquently. ---------------------------------------------------------------------- jcmontherock · 2021-04-20 09:03 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 ? ---------------------------------------------------------------------- PascalDragon · 2021-04-20 14:39 Quote from: jcmontherock on April 20, 2021, 11:03:08 amI 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. ---------------------------------------------------------------------- pcurtis · 2021-04-20 14:56 I think he means is it enough just to Free or is it better to FreeAndNil? ---------------------------------------------------------------------- howardpc · 2021-04-20 16:55 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. ---------------------------------------------------------------------- ASerge · 2021-04-20 17:07 Quote from: pcurtis on April 20, 2021, 04:56:34 pmI 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).