FreeAndNilroutine instead of
Well, when someone talks about object creation and destruction, he usually imagine something like this:
... var SomeObj: TSomeClass; ... SomeObj := TSomeClass.Create; try ... finally SomeObj.Free; end; ...However, I want to show that you should avoid "
Free" call, whenever possible - by replacing it with call to
FreeAndNil, for example:
... var SomeObj: TSomeClass; ... SomeObj := TSomeClass.Create; try ... finally FreeAndNil(SomeObj); end; ...Please, note, that I mean replacing
FreeAndNileverywhere. I talk not about just using
FreeAndNil, when you want to use
Assigned(SomeObj), but I really mean everywhere - by do not using
Freeat all. Yes, including cases with local variables.
Why? The reason is simple: there is no reason for not-doing it. And this post explains why it is so.
When you tell this to common Delphi developer, there are high chances that he'll vote against it, saying:
Free + nilis not full equivalent of
FreeAndNilclears pointer first and calls destructor second. If your code uses this reference - it will no longer work. For example, if we clear class field, but some internal class uses it during destruction process.
Well, I count it as advantage. It helps to catch bad-design. Because you just described a case, when your code either uses variable instead of
SomeObj) or accesses a partial-constructed object (actually, it is more like partially deleted object now). And by using
FreeAndNilyou can catch these cases.
Yes, such situations can be made "by-design", but even so - you will detect an error immediately (obviosly, there will be Access Violation), so you can revert changes back, if you don't want to redesign your code.
2. So what are examples of righteous/warrantable usage of
Hmm, it is not very clear, what example can be provided here. Excluding complicated examples (like in previous block), your code will work the very same way - with or without
Free -> FreeAndNil
- it is a pure optional action.
You can compare
FreeAndNilwith seat (safety) belts in cars: if you application runs normally - then
FreeAndNilwon't be useful. But if your code mess up with something - then
FreeAndNil(as seat belts too) will protect you from consequences. By clearing the reference,
FreeAndNilwill help you to catch your wrong access immediately. Without it (i.e. by using
Freeonly), your code may continue to run (even without raising an exception) and gave the wrong results or damage global state. It is quite dangerous.
FreeAndNilis still not enough to fully cover those bad cases - because you can access one object through multiply variables.
FreeAndNilwill clear one reference, but it won't touch others. A good example here is all kinds of lists of objects.
3. There is no need for
FreeAndNilhere! (i.e.: local variables)
Well, local variable can be refactored into global later.
FreeAndNilwill protect you from misuses (just Free is not). Large amount of code is done by using copy-paste. That is why someone can pick your code, copy it into another place (where variable has different scope or is used multiply times), then he'll be in trouble - if you didn't use
FreeAndNil(and this "he" may be even you, but few months later). Besides, if you have large routine then you may just not notice, that you have used variable few times (for example - in cycle). By always using
FreeAndNilyou'll make your code bullet-proof for modifications.
OK, that was a weak point. More important is that it is just convient, when you have
FreeAndNileverywhere, instead of mix of
Free/FreeAndNil. And you don't even need to think about it: "gosh, should I put
FreeAndNilhere or just
If you think that
FreeAndNilis still overkill in certain case - then why don't you use
Destroycall? Indeed, the
Freeis overkill in many situations too!
Note, that object's destructor is not called in 99% of Delphi's code (a call to procedure is used instead). Then why don't we take a step further and don't use
FreeAndNilinstead? The benefit of using
FreeAndNilis far greater then benefit from using
Freeinstead of Destroy. Why? Well, if the first case we got the protection from very tricky mistakes (like I said - it is not panacea, but still a good bonus). And in the second case you got only ability to skip writing additional "if". Why? Because if you call
Destroyfor nil-variable, you'll get an AV immediately (because
nil, so any access to object's field will trigger an undoubted AV). So, there is no problem at all - you will fix the code instantly. Compare this with case, when your code silently produce wrong results!
Furthermore, you can not giveup for a bonus "less writing" by implementing a routine "F", which simply calls
FreeAndNil. Or you can use a live template (as I do).
Destroyis recommended by Borland/CodeGear/Embarcadero! And I never heard of such recommendation for
Yeah, right. Like those help files were updated ever since dinosaurs age :)
Well, we already examined arguments that
Free -> FreeAndNiltransition will have more benefits than (already happened) transition
Destroy -> Free. Now, don't you think that argument of not having official approval from B/CG/E does look quite dull?
5. Nevertheless, majority of people (who heard about this idea) will continue to claim that this is still overkill.
The most called reason is the force of the habit: "I write
Freeautomatically, even without thinking".
Well, actually, this argument is quite serious.
By in this post, I want to show you that there are good reasons to reconsider/change this habbit. Of course, there should be a really good reson for broking your habbits. And here it comes...
6. Safety of your code.
Many people says (and they, indeed, believe so) that experienced programmer can use
FreeAndNilonly in nessesary places. In all other cases there is no need to clear the object's reference - so you can use Free.
But that is so wrong: you can not know that.
Imagine, that destructor of your object deletes its object-field by using
Free(such common action, right?). The destructor for this sub-object calls a virtual method as part of its destruction process. This method can be empty in base class. Well, so far so good.
Now, someone (or may be you, few months later) will take these classes and override this virtual method. Now he will call another (virtual) method, which belongs to your first mentioned object. And this method (may be also in yet another child class) will try to use already deleted field in your first object. Suppose that this access will run ok (i.e. memory manager do not release this memory yet), but the global state of the application will be damaged forever. Ooops.
FreeAndNilwill guard you from this situation (by raising 100% AV), and
Why did I mention virtual methods here? That is why you cann't say: "I know what I am doing - there is no need for
FreeAndNilhere". As you can see - you can not know that! Yes, two of your base classes is all good with it, but the very usual code in child classes can lead to the darkest error in the entire class hierarchy. Yes, it is not actually your fault (unless you are also responsible for child classes too), but shouldn't your code be ideal? And, yes, there is a bug in child class (by calling inadmissible method), but how will you catch it? Without
FreeAndNilit is very hard to do.
Okay, even if you still insist on putting
FreeAndNilonly, when it is nessesary - then we just gave an example, when it is simply not obvious. If you have a habbit of using
Free, then you can not even think about considering this case as worth adding
FreeAndNil! That is where all problems come. You'll just put
Freecall here (as usual) and go somewhere else. And then spend a few days for debugging this tiny, nasty problem later.
FreeAndNileverywhere you'll dispose those problems ("should I put it there or not?") - just put it everywhere! Like I said:
FreeAndNil- is a safety belts. And realizing it is the only thing left.
Summary: from my point of view - the bonus of protection against fickle/implicit errors outweigh the need to change the habbit.
Why wait? Why don't use
FreeAndNileverywhere, starting today? If you'll make this your habbit - then you lose nothing, but gain very powerful bonus.
Nevertheless, I suspect that many Delphi programmers, even if they admit this idea, won't change their practice - just because "someone has said something". They do not meet with this situation - then it do not exists. So they'll wait until the bug strike them hard. I'll repeat it again:
FreeAndNilis a safety belt. It protect you from bugs, that not happens yet.
Remark: this long post is just my opinion - feel free to reject it, if you (still) don't like it.
When you reference an object via more than one reference, you can mistakenly use already disposed object or free the very same object twice. The
FreeAndNilgives you protection only if you mistakenly use the object after its dispose, when you have only one reference.
So, even if you use
FreeAndNil, you still need an additional checks. And if you have large project and suddenly changes all
FreeAndNil- then there are good chances then you'll run into problems. You'll probably detect many kind of misuses. To track down these problems you'll need a tool.
Such checks can be found in EurekaLog. We will talk about its memory-related features in more details later (yes, about FastMM too), and now I want to give only brief overview.
EurekaLog's memory-leak feature settingsOnce enabled, this feature can detect a various memory misuse cases and report them through usual exception notification process in EL. Those cases includes double-free and writes to already freed memory. Similar features are very common in advanced memory managers (like FastMM, for example).
It is quite powerful feature, but just don't forget that EurekaLog is a debugging tool. It is not essential part of Delphi language. You should not write code, which relies on its presence. I.e. you should not forget about
FreeAndNil, hoping that EurekaLog will handle all bad cases for you. Besides, there still can be complex (and, actually, rare) situations, when EurekaLog's features can not catch attempt of invalid memory access (it is not limitation of EL, the same is correct for other tools too). More on this topic later.
Apart from using
FreeAndNiland diagnostic features in EurekaLog or MM, you should try to minimize references to each objects and try to use some sort of automatic management. For example, if your object can be included in the list, then it is good to add code, which removes object from any list it belongs to on deletion (there is an example in VCL - it is Components list-property).
Another approach is using interfaces with reference counting. Well, actually, you should be careful there: if you mix manual control of life-time (manual call to destructor) and automatic control (using reference counting in interfaces) - then things will go from bad to worse. But if you use only pure interfaces, then you'll automatically get rid of such errors: compiler (well, your application at runtime) will look after your objects, not allowing their misuses.