Recently, I came across a forum where somebody described FreeAndNil
as an “abomination” and I think that’s a bit over the top.
Let’s unpack this topic ca refully, with technical clarity and an eye for proportion.
FreeAndNil(SomeObject)
is just syntactic sugar for:
if SomeObject <> nil then
begin
SomeObject.Free;
SomeObject := nil;
end;
The actual implementation of FreeAndNil
looks like this (simplified):
procedure FreeAndNil(var Obj: TObject);
var
Temp: TObject;
begin
Temp := Obj;
Obj := nil;
Temp.Free;
end;
Performance: How much does it cost?
FreeAndNil adds an assignment operation in addition to the Free
call. The cost of assigning nil
to a variable is measured of 1 nanosecond or less when hidden behind caches and compiler optimizations.
A 4 GHz CPU means 4 billion cycles per second.
1 second = 1,000,000,000 nanoseconds (ns)
So: 1 cycle = 1 / 4,000,000,000 seconds ≈ 0.25 nanoseconds (ns)
4 GHz CPU → 0.25 ns per cycle
Context:
- That’s the idealized number for the base clock rate.
- Real execution time per instruction varies due to:
- Instruction complexity (e.g., a simple
MOV
might take 1 cycle; aDIV
could take dozens) - Pipeline stages
- Cache hits/misses
- Branch prediction
- Out-of-order execution
- Instruction complexity (e.g., a simple
- Memory access (RAM) latency is far worse: typically 50-100 ns for L3 cache misses, ~100 ns or more for DRAM.
Performance: Talking about Goliath and dwarfs
A single file open (CreateFile
API) or read/write operation will take thousands to millions of times longer than any conceivable number of FreeAndNil
calls in your application’s lifetime.
If you ever wrote 10,000 FreeAndNil
calls in your entire career, and they each added a generous 5 nanoseconds of overhead, you would be spending around 50 microseconds—total, over years of coding. By comparison, opening an empty file on an SSD takes about 10,000 microseconds. So one FileOpen wipes out 200,000 lifetimes of FreeAndNil usage.
We’re literally talking about dust on the scales of performance.
FreeAndNil is effectively noise compared to anything involving RAM or I/O.
Why Use FreeAndNil?
Despite this, there are valid reasons to use FreeAndNil
:
- Safety in Defensive Programming: Setting a reference to
nil
after freeing makes accidental future accesses raise an immediateAccess Violation
(AV), rather than weird behavior or subtle memory corruption. - Error Handling: In destructors or error-recovery code, calling
FreeAndNil
ensures that if code later tries to free the object again, it will safely no-op. - Debugging: Especially in large legacy codebases, setting to
nil
after freeing can make bugs easier to trace. This is a place where FreeAndNil helped me a lot. I have discovered so many bugs in old code by replacing Free with FreeAndNil.
Why Some Hate It So Badly
The criticism stems more from philosophy than performance:
- Code smell: Frequent use of
FreeAndNil
can be a signal of poor object lifetime management. - Masking bugs: Setting things to
nil
might hide bad code rather than forcing the developer to fix ownership issues.
This stance is largely from a purist, clean-code perspective, arguing that it’s better to write code that doesn’t need defensive nil-
ing in the first place. This perspective can be right SOMETIMES: abusive use of FreeAndNil could indicate poor architecture. But it is not a rule!
Saying that FreeAndNil indicates bad design is like blaming an electronic engineer for putting a fuse into his design because a fuse could indicate that the circuit might burn, or putting a spare wheel/repair tools onto a car because it indicates that the car might break down.
I use FreeAndNil because it “costs” nothing and truly detects “use after free”.
Correlation is not causality
As the presence of a pack of cigarettes in my pocket does not prove the existence of lung cancer (not that I smoke), the presence of FreeAndNil in a program proves nothing without the analysis of the code! Before pointing the fingers to a line of code that has FreeAndNil in it, people should analyze the code base and point to the actual issue (if any). See, it is easier to say it than to do it! Do read about “burden of proof“.
Conclusion
If you want to write clean, disciplined, modern Delphi code, focus on ownership models, smart pointers (e.g., TObjectList<T>
with OwnsObjects := True
), and RAII patterns where appropriate. If you find yourself checking often if an object is nil (I am not talking about assertions here) then you might have indeed an architecture design. Basically don’t store information in the existence (or nonexistence) of a nil. But note that it is not possible in all cases to do so. There are instances where a field has to be nil (for example you have a JPEG object that does not have an EXIF object associated).
That being said, I do use exclusively FreeAndNil instead of Free (but I do not need to check my object for nil). As I said, FreeAndNil is useful because if I ever make the mistake of using an object after Free, I will know immediately. It is a “silver bullet” that comes for free. And when it comes for free, there is nothing wrong with this type of defensive programming.
Is the debate meaningless?
In my opinion, yes. Unless you can come with proof that a program architecture is wrong, just jumping around and screaming and pointing to a FreeAndNil, means nothing!
You can start your research from the existence of a FreeAndNil, but you cannot conclude anything just from the existence of that FreeAndNil.