I'm somewhat new to Delphi, and this question is just me being curious. (I also just tried using it by accident only to discover I'm not supposed to.)
If you look at the documentation for TObject.InitInstance it tells you not to use it unless you're overriding NewInstance. The method is also public. Why not make it protected if the user is never supposed to call it?
Since I was around when this whole Delphi thing got started back around mid-1992, there are likely several answers to this question. If you look at the original declaration for TObject in Delphi 1, there weren't any protected/private members on TObject. That was because very early on in the development of Delphi and in concert with the introduction of exceptions to the language, exceptions were allocated from a different heap than other objects. This was the genesis of the NewInstance/InitInstance/CleanupInstance/FreeInstance functions. Overriding these functions on your class types you can literally control where an object is allocated.
In recent years I've used this functionality to create a cache of object instances that are literally "recycled". By intercepting NewInstance and FreeInstance, I created a system where instances are not returned to the heap upon de-allocation, rather they are placed on a lock-free/low-lock linked list. This makes allocating/freeing instances of a particular type much faster and eliminates a lot of excursions into the memory manager.
By having InitInstance public (the opposite of which is CleanupInstance), this would allow those methods to be called from other utility functions. In the above case I mentioned, InitInstance could be called on an existing block of memory without having to be called only from NewInstance. Suppose NewInstance calls a general purpose function that manages the aforementioned cache. The "scope" of the class instance is lost so the only way to call InitInstance is of it were public.
One of these days, we'll likely ship the code that does what I described above... for now it's part of an internal "research" project.
Oh, as an aside and also a bit of a history lesson... Prior to the Delphi 1 release, the design of how Exception instances were allocated/freed was returned to using the same heap as all the other objects. Because of an overall collective misstep it was assumed that we needed to allocate all Exception object instances to "protect" the Out of memory case. We reasoned that if we try and raise an exception because the memory manager was "out of memory", how in the blazes would we allocate the exception instance!? We already know there is no memory at that point! So we decided that a separate heap was necessary for all exceptions... until either Chuck Jazdzewski or Anders Heijlsberg (I forget exactly which one), figured out a simple, rather clever solution... Just pre-allocate the out of memory exception on startup! We still needed to control whether or not the exception should ever actually be freed (Exception instances are automatically freed once handled), so the whole NewInstance/FreeInstance mechanism remained.
Well never say never. In the VCL too much stuff is private and not virtual as it is, so I kinda like the fact that this stuff is public.
It isn't really necessary for normal use, but in specific cases, you might use it to allocate objects in bulk. NewInstance reserves a bit of memory for the object and then calls InitInstance to initialize it. You could write a piece of code that allocates memory for a great number of objects in one go, and then calls InitInstance for different parts of that large block to initialize different blocks in it. Such an implementation could be the base for a flyweight pattern implementation.
Normally you wouln't need such a thing at all, but it's nice that you can if you really want/need to.
How it works?
The fun thing is: a constructor in Delphi is just some method. The Create method itself doesn't do anything special. If you look at it, it is just a method as any other. It's even empty in TObject!
You can even call it on an instance (call MyObject.Create instead of TMyObject.Create), and it won't return a new object at all. The key is in the constructor keyword. That tells the compiler, that before executing the TAnyClass.Create method, it should also construct an actual object instance.
That construction means basically calling NewInstance. NewInstance allocates a piece of memory for the data of the object. After that, it calls InitInstance to do some special initialization of that memory, starting with clearing it (filling with zeroes).
Allocating memory is a relatively expensive task. A memory manager (compiled into your application) needs to find a free piece of memory and assign it to your object. If it doesn't have enough memory available, it needs to make a request to Windows to give it some more. If you have thousands or even millions of objects to create, then this can be inefficient.
In those rare cases, you could decide to allocate the memory for all those objects in one go. In that case you won't call the constructor at all, because you don't want to call NewInstance (because it would allocate extra memory). Instead, you can call InitInstance yourself to initialize pieces of your big chunk of memory.
Anyway, this is just a hypotheses of the reason. Maybe there isn't a reason at all. I've seen so many irrationally applied visibility levels in the VCL. Maybe they just didn't think about it at all. ;)
It gives developers a way to create object not using NewInstance (memory from stack/memory pool)
Related
In another question, I found out that the Assigned() function is identical to Pointer <> nil. It has always been my understanding that Assigned() was detecting these dangling pointers, but now I've learned it does not. Dangling Pointers are those which may have been created at one point, but have since been free'd and haven't been assigned to nil yet.
If Assigned() can't detect dangling pointers, then what can? I'd like to check my object to make sure it's really a valid created object before I try to work with it. I don't use FreeAndNil as many recommend, because I like to be direct. I just use SomeObject.Free.
Access Violations are my worst enemy - I do all I can to prevent their appearance.
If you have an object variable in scope and it may or may not be a valid reference, FreeAndNil is what you should be using. That or fixing your code so that your object references are more tightly managed so it's never a question.
Access Violations shouldn't be thought of as an enemy. They're bugs: they mean you made a mistake that needs fixed. (Or that there's a bug in some code you're relying on, but I find most often that I'm the one who screwed up, especially when dealing with the RTL, VCL, or Win32 API.)
It is sometimes possible to detect when the address a pointer points to resides in a memory block that is on the heap's list of freed memory blocks. However, this requires comparing the pointer to potentially every block in the heap's free list which could contain thousands of blocks. So, this is potentially a computationally intensive operation and something you would not want to do frequently except perhaps in a severe diagnostic mode.
This technique only works while the memory block that the pointer used to point to continues to sit in the heap free list. As new objects are allocated from the heap, it is likely that the freed memory block will be removed from the heap free list and put back into active play as the home of a new, different object. The original dangling pointer still points to the same address, but the object living at that address has changed. If the newly allocated object is of the same (or compatible) type as the original object now freed, there is practically no way to know that the pointer originated as a reference to the previous object. In fact, in this very special and rare situation, the dangling pointer will actually work perfectly well. The only observable problem might be if someone notices that the data has changed out from under the pointer unexpectedly.
Unless you are allocating and freeing the same object types over and over again in rapid succession, chances are slim that the new object allocated from that freed memory block will be the same type as the original. When the types of the original and the new object are different, you have a chance of figuring out that the content has changed out from under the pointer. However, to do that you need a way to know the type of the original object that the pointer referred to. In many situations in native compiled applications, the type of the pointer variable itself is not retained at runtime. A pointer is a pointer as far as the CPU is concerned - the hardware knows very little of data types. In a severe diagnostic mode it's conceivable that you could build a lookup table to associate every pointer variable with the type allocated and assigned to it, but this is an enormous task.
That's why Assigned() is not an assertion that the pointer is valid. It just tests that the pointer is not nil.
Why did Borland create the Assigned() function to begin with? To further hide pointerisms from novice and occasional programmers. Function calls are easier to read and understand than pointer operations.
The bottom line is that you should not be attempting to detect dangling pointers in code. If you are going to refer to pointers after they have been freed, set the pointer to nil when you free it. But the best approach is not to refer to pointers after they have been freed.
So, how do you avoid referring to pointers after they have been freed? There are a couple of common idioms that get you a long way.
Create objects in a constructor and destroy them in the destructor. Then you simply cannot refer to the pointer before creation or after destruction.
Use a local variable pointer that is created at the beginning of the function and destroyed as the last act of the function.
One thing I would strongly recommend is to avoid writing if Assigned() tests into your code unless it is expected behaviour that the pointer may not be created. Your code will become hard to read and you will also lose track of whether the pointer being nil is to be expected or is a bug.
Of course we all do make mistakes and leave dangling pointers. Using FreeAndNil is one cheap way to ensure that dangling pointer access is detected. A more effective method is to use FastMM in full debug mode. I cannot recommend this highly enough. If you are not using this wonderful tool, you should start doing so ASAP.
If you find yourself struggling with dangling pointers and you find it hard to work out why then you probably need to refactor the code to fit into one of the two idioms above.
You can draw a parallel with array indexing errors. My advice is not to check in code for validity of index. Instead use range checking and let the tools do the work and keep the code clean. The exception to this is where the input comes from outside your program, e.g. user input.
My parting shot: only ever write if Assigned if it is normal behaviour for the pointer to be nil.
Use a memory manager, such as FastMM, that provides debugging support, in particular to fill a block of freed memory with a given byte pattern. You can then dereference the pointer to see if it points at a memory block that starts with the byte pattern, or you can let the code run normallly ad raise an AV if it tries to access a freed memory block through a dangling pointer. The AV's reported memory address will usually be either exactly as, or close to, the byte pattern.
Nothing can find a dangling (once valid but then not) pointer. It's your responsibility to either make sure it's set to nil when you free it's content, or to limit the scope of the pointer variable to only be available within the scope it's valid. (The second is the better solution whenever possible.)
The core point is that the way how objects are implemented in Delphi has some built-in design drawbacks:
there is no distinction between an object and a reference to an object. For "normal" variables, say a scalar (like int) or a record, these two use cases can be well told apart - there's either a type Integer or TSomeRec, or a type like PInteger = ^Integer or PSomeRec = ^TSomeRec, which are different types. This may sound like a neglectable technicality, but it isn't: a SomeRec: TSomeRec denotes "this scope is the original owner of that record and controls its lifecycle", while SomeRec: PSomeRec tells "this scope uses a transient reference to some data, but has no control over the record's lifecycle. So, as dumb it may sound, for objects there's virtually no one who has denotedly control over other objects' lifecycles. The result is - surprise - that the lifecycle state of objects may in certain situations be unclear.
an object reference is just a simple pointer. Basically, that's ok, but the problem is that there's sure a lot of code out there which treats object references as if they were a 32bit or 64bit integer number. So if e.g. Embarcadero wanted to change the implementation of an object reference (and make it not a simple pointer any more), they would break a lot of code.
But if Embarcadero wanted to eliminate dangling object pointers, they would have to redesign Delphi object references:
when an object is freed, all references to it must be freed, too. This is only possible by double-linking both, i.e. the object instance must carry a list with all of the references to it, that is, all memory addresses where such pointers are (on the lowest level). Upon destruction, that list is traversed, and all those pointers are set to nil
a little more comfortable solution were that the "one" holding such a reference can register a callback to get informed when a referenced object is destroyed. In code: when I have a reference FSomeObject: TSomeObject I would want to be able to write in e.g. SetSomeObject: FSomeObject.OnDestruction := Self.HandleDestructionOfSomeObject. But then FSomeObject can't be a pointer; instead, it would have to be at least an (advanced) record type
Of course I can implement all that by myself, but that is tedious, and isn't it something that should be addressed by the language itself? They also managed to implement for x in ...
Destructors in Delphi are usually named "Destroy", however as far as i understand you can also
name destructors differently
have multiple destructors
Is there any reason why this was implemented this way? What are the possible use cases for differently named / multiple destructors?
In theory you can manually call different destructors to free different external resources, like breaking ref-counting loops, deleting or just closing file, etc.
Also, since the Object Pascal language does not have those magical new/delete operations, there just should be some identifier to call for disposing of the object.
I'd prefer to look at that in retrospect.
"Turbo Pascal with Objects" style objects have both - you call a "magical" Dispose procedure but explicitly specify a destructor to call, since language itself did not knew what to choose. Similarly "magic" procedure New had to be supplied with a manually selected constructor.
http://www.freepascal.org/docs-html/rtl/system/dispose.html
http://putka.acm.si/langref/turboPascal/0547.html
http://www.freepascal.org/docs-html/rtl/system/new.html
http://putka.acm.si/langref/turboPascal/04A4.html
This however violates DRY principle: compiler knows that we are calling d-tor or c-tor, but yet we have to additionally call those "New" and "Dispose" functions. In theory that probably provided to decouple memory allocation and information feeding and combine them anyway we'd like. But i don't think this feature was actually used anything wide.
Interesting that the same design is used in Apple Objective C. You 1st allocate memory for the object and after that you call a constructor for that new instance: http://en.wikipedia.org/wiki/Objective-C#Instantiation
When that model was streamlined for Delphi few decisions was made to make things more simplified (and unified). Memory [de]allocation strategy was shifted to the class level, rather than call-site. That made the redundancy of both calling "New" and named constructor very contrast. One had to be dropped.
C++/C#/Java chosen to retain a special language-level keywords for it, using overloaded functions to provide different c-tors. Perhaps that corresponds to USA style of computer languages.
However Pascal at its core has two ideas: verbosity and small vocabulary. Arguably they can be tracked in other European-school languages like Scala. If possible, the keywords should be removed from language itself and moved to external modules - libraries that you can add or remove from project. And overloaded functions were introduced much later to the language and early preference was to surely have two differently named (self-documenting) function names.
This both ideas probably caused Delphi to remove "magic" procedures and to deduce object creation/destruction at the call-site just by used function names. If you call MyVar.Destroy then compiler looks at the declaration of .Destroy and knows we are deleting the object. Similarly it knows TMyType.CreateXXX(YYY,ZZZ) is an object instanbtiation due to the way CreateXXX was declared.
To make c-tor and d-tor no-named like in C++, Delphi would have to introduce two more keywords to the language level, like those C++ new and delete. And there seems to be no clear advantage in that. At least personally i better like Delphi way.
PS. I had to add there one assumption: we are talking about real C++ and Delphi languages as they were around 1995. They only featured manual memory control for heap-allocated objects, no garbage collection and no automatic ref-counting. You could not trigger object destruction by assigning variable with nil/NULL pointer.
I have implemented the FlyWeight pattern in my Delphi application. Everything has worked great, everything is a lot faster and takes less memory, but there is one thing I am worried about.
My implementation will only work as long as client code never calls Free() on the shared objects. In the Flyweight pattern, the FlyweightFactory itself is supposed to "maintain a reference to flyweights" i.e. to the shared objects.
My problem is that there is no (obvious) way to stop other code from destroying the objects once they have a reference. I could live with this, but it would be a "big win" if I could pass these objects round freely without worrying about accidental freeing.
To show a (contrived) example:
flyweight1:=FlyweightFactory.GetFlyweight(42);
WriteLn('Description is '+flyweight.Description);
flyweight1.Free;
flyweight2:=FlyweightFactory.GetFlyweight(42);
WriteLn('Description is '+flyweight.Description);
// Object has already been Freed!; behaviour is undefined
I have considered overriding the destructor as shown here to stop the flyweight object being freed altogether. This is not an option in my case as
a) I only want to stop cached objects from being Freed, not objects that aren't part of the cache. There is a lot of legacy code that doesn't use the cache; they still need to create and free objects manually.
b) I do want the FlyweightFactory to Free the objects during finalization; I agree with Warren P that a "zero leaked memory" policy is best.
I'll leave with a quote from the Flyweight chapter of GoF
Sharability implies some form of
reference counting or garbage
collection to reclaim storage when
it's no longer needed. However,
neither is necessary if the number of
flyweights is fixed and small. In that
case, the flyweights are worth keeping
around permanently.
In my case the flyweights are "fixed" and (sufficiently) small.
[UPDATE See my answer for details of how I solved this problem]
My answer to the question you link to still applies. The objects must know by means of a private boolean flag that they are cached objects. Then they can elect not to destroy themselves in Destroy and FreeInstance. There really is no alternative if you want to allow Free to be called.
To deal with finalization you would want to add the cached objects to a list of cached objects. That list of objects can be freed at finalization time. Of course the flag to disable freeing would have to be reset whilst you walked the list.
Having made this point regarding finalization, I would advise you to register an expected memory leak and just leak this memory. It makes the code much simpler and there's nothing to lose. Any memory you don't free will be reclaimed by the OS as soon as your executable closes. One word of caution: if your code is compiled into a DLL then leaking could be troublesome if your DLL is loaded, unloaded, loaded again etc.
What all this is telling you is that you are swimming against the current. Is it possible that you could achieve your goals with a different solution that fitted better with the way Delphi is steering you?
I suggest to add a reference count in order to known if your shared object is still used.
Every client should use the pattern AddRef / Release (AddRef increases the count; Release decrements it; if count reaches zero Free is called)
The AddRef may be called directly by your GetFlyweight method; Release has to be used instead of Free.
If you refactor your class and extract an interface from it the AddRef/Release pattern in naturally implemented in then interface implementation. (You could derive from TInterfacedObject or implement IInterface by your self)
Ideally you seldom want 2 ways of using the same things. It just complicates matters in the long run. In 6 months time, you might not be sure whether a particular piece of code is using the new flyweight paradigm or the old paradigm.
The best way to prevent someone calling Free or Destroy is to make sure it's not even there. And within the Delphi world, the only way to do that is to use interfaces.
To expand on your contrived example:
type
TFlyweightObject = class
public
constructor Create(ANumber: Integer);
function Description: string;
end;
TFlyweightFactory = class
public
function GetFlyweight(ANumber: Integer): TFlyweightObject;
end;
This being an object can easily be destoyed by a rogue client. You could make the following changes:
type
IFlyweight = interface
//place guid here
function Description: string;
end;
TFlyweightObject = class(TInterfacedObject, IFlyweight)
public
constructor Create(ANumber: Integer);
function Description: string;
end;
TFlyweightFactory = class
public
function GetFlyweight(ANumber: Integer): IFlyweight;
end;
Now any code that is updated to use the flyweight paradigm is forced to use it as intended. It's also easier to recognise the old code that still needs to be refactored because it doesn't use the interface. Old code would still construct the "flyweight" object directly.
You could also hide a destructor by making it protected or private. Programmers won't see it outside the scope of the unit in which it is declared in.
But I am posting this answer more like a curiosity because this will not prevent freeing an object by using FreeAndNil or by using a "Protected Hack"
I managed to get around the problems I cited in my original question using the following techniques, suggested by David Heffernan in his answer.
a) I only want to stop cached objects
from being Freed, not objects that
aren't part of the cache. There is a
lot of legacy code that doesn't use
the cache; they still need to create
and free objects manually.
I fixed this by subclassing the Flyweight class and overriding destroy, BeforeDestruction and FreeInstance in the subclass only. This left the parent class as is. The cache contains instances of the subclass (which can't be freed), whereas objects outside the cache can be freed as per usual.
b) I do want the FlyweightFactory to
Free the objects during finalization;
I agree with Warren P that a "zero
leaked memory" policy is best.
To solve this, I added a private boolean flag that has to be set to true before the object can be freed. This flag can only be set from the Cache Unit, it is not visible to other code. This means that the flag cannot be set outside by code outside the cache.
The destructor just looks like this:
destructor TCachedItem.destroy;
begin
if destroyAllowed then
inherited;
end;
If client code trys to Free a cached object, the call will have no effect.
I'm still something of a newbie, and I know my thinking is incorrect; I just don't know where ...
Just about everything in Delphi is descended from TObject. What if everything instead descended from a TInterfaceObject that implemented some trivial interface (e.g., "INamable," with a single method that returned a class's name string)? Since TObject already has a property that returns a name string, you wouldn't need to add anything to additional classes.
In other words, a TInterfacedObject would inherit from TObject (or something high up in the hierarchy), and everything currently descending from TObject would now descend from this new class. Wouldn't this mean everything was now reference counted?
If you can spot where my knowledge is lacking, I'd love to learn. Thanks, as always -- Al C.
It's not clear whether you're asking:
Why didn't Borland do this, when they originally developed Delphi?
Why don't Embarcadero do this, in a future version of Delphi?
Why don't I do this, with my own user data types?
Wouldn't this mean everything was now reference counted?
Yes it would.
However, you don't necessarily want everything to be ref-counted: every little integer, every string, every boolean, every element in an array ... if for no other reason that the implementation of ref-counting adds some overhead, e.g. a little extra memory per object, perhaps insignificant for large objects but proportionally more significant if applied to every tiny object.
Also, see also Garbage Collector For Delphi Objects and Components which says (quote),
Delphi provides three ways of object management :
Create/destroy the objects using try..finally.
Use TComponent descendants - create a component and let its owner free it.
Interfaces - when the reference count for an interface becomes 0 the
object which implements it is
destroyed.
The Delphi help says you shouldn't mix
the TComponent owner approach with the
interface memory management, but ...
Would this be garbage collection?
Not quite; mere reference-counting isn't as robust as garbage-collection:
With reference-counting, if you have two reference-counted instances each holding a reference to the other, then they're not released automatically. To release them you would need to break this 'circular reference' (i.e. explicitly tell one of them to release its reference to the other).
With true garbage-collection, the garbage-collector would notice that those two istance aren't referenced from anywhere else, and release them both.
Update
If you annotate your potentially circular references as [weak] references, then they will get destroyed ok. But prior to Delphi 10.1 Berlin this only works in the NexGen compilers (i.e. those that use LLVM under the hood). From 10.1 Berlin onwards these [weak] references work everywhere.
It wouldn't be working garbage collection because interfaces use a very simple reference-counting system, and circular references, which are very common in Delphi code, break simple ref-counting.
No, because of two things:
Even if a class implements an interface it does not automatically make it reference counted. Only if you actually use it to implement that interface the reference counting will have any effect.
As others already said: Reference counting in interfaces will result in the class instance to be freed immediately when the reference count reaches 0. It is an implicit call to the Free method at that point in code. This will fail e.g. if two objects reference each other. True garbage collection will free the objects not when they go out of scope but when memory is needed, so there is no performance impact every time the reference count reaches 0 because the object will just continue to exist. In addition a good garbage collector will detect the isolated circular references (e.g. A references B references C references A but nothing else references any of these objects) and will free these objects as well.
Garbage collection is different from simple ref counting. You can have automatic deletion when a ref count reaches 0, but that too is not garbage collection. Garbage collection means letting go of your ability to control when things are deleted from memory, and allowing the underlying language's implementation to optimize the behviours. You stop paying attention to reference counts, and trust in the dynamic behaviours of a particular implementation of garbage collection.
Naturally, garbage collection uses a system of reference counting to know when something is no longer referenced, but that is a small piece of the puzzle.
Reference counting is a form of garbage collection, but not a very good one. It is used by some languages (python I think) although often with cycle detection.
Even if you descended from TInterfaceObject, the object is not reference counted and thus garbage collected unless you only use the interface reference and not the object reference.
I.e. you would need to use
Var
nameable: IMyInterface;
begin
nameable:= IMyInterface.Create();
nameable.x(y);
etc
end;
This implies that your interface needs to support already the methods and properies that you require which quickly becomes tedious as you need to create an interface for each class.
It can be done reasonably easily in D2009 or later though. See Barry Kelly's implimentation of smart pointers. The usual reference countng cavets apply though.
In my Delphi7 this code
var MStr: TMemoryStream;
...
FreeAndNil(MStr);
MStr.Size:=0;
generates an AV: Access violation at address 0041D6D1 in module 'Project1.exe'. Read of address 00000000.
But somebody insists that it should not raise any exception, no matter what. He also says that his Delphi 5 indeed raises no exceptions. He calls this a “stale pointer bug”.
In other words he says that FreeAndNil cannot be used as debugger to detect a double attempt to free an object or to use a freed object.
Can anybody enlighten me? Should this raise and error (always/randomly) or the program should run over this bug without problems?
Thanks
I ask this because I believe I have a "double free object" or "free and re-access" bug in my program. How can I fill the memory allocated to an object with zeros AFTER I freed the object? I want this way to detect where the bug is, by getting and AV.
Initially, I hoped that if I set the object to FreeAndNil, I will ALWAYS get an AV when trying to re-access it.
It's always wrong to use methods or properties of a null reference, even if it appears to work sometimes.
FreeAndNil indeed cannot be used to detect double frees. It is safe to call FreeAndNil on an already-nil variable. Since it's safe, it doesn't help you detect anything.
This is not a stale-pointer bug. This is a null-reference bug. A stale-pointer bug is when you have freed an object but not cleared all variables that referenced it. Then the variable still holds the old address of the object. Those are very hard to detect. You can get such a bug like this:
MStr := TMemoryStream.Create;
MStr.Free;
MStr.Size := 0;
You can also get one like this:
MStr := TMemoryStream.Create;
OtherStr := MStr;
FreeAndNil(MStr);
OtherStr.Size := 0;
Using MStr.Size after you have freed the object MStr referenced is an error, and it should raise an exception. Whether it does raise an exception depends on the implementation. Maybe it will, and maybe it won't. It's not random, though.
If you're searching for a double-free bug, you can use the debugging aides that FastMM provides, as others have suggested as well. It works by not actually releasing the memory back to the operating system, or even back to Delphi's internal free-memory pool. Instead, it writes known-bad data into the object's memory space, so when you see those values, you'll know you're reading from something that you already freed. It also modifies the object's VMT so that the next time you call a virtual method on that object reference, you'll get a predictable exception, and it will even tell you which supposedly freed object you tried to use. When you attempt to free the object again, it can tell you not only that you already freed it, but also where it was freed the first time (with a stack trace), and where it was allocated. It also collects that information to report about memory leaks, where you freed an object less than one time instead of more.
There are also habits you can use to avoid the issue for future code:
Reduce the use of global variables. A global variable could be modified by any code throughout the program, forcing you to wonder whenever you use it, "Is this variable's value still valid, or did some other code free it already?" When you limit the scope of a variable, you reduce the amount of code you have to consider in your program when looking for reasons a variable doesn't have the value you expect.
Be clear about who owns an object. When there are two pieces of code that have access to the same object, you need to know which of those pieces of code owns the object. They might each have a different variable for referencing the object, but there's still just one object there. If one piece of code calls FreeAndNil on its variable, that still leave's the other code's variable unchanged. If that other code thinks it owns the object, then you're in trouble. (This concept of owner is not necessarily tied to the TComponent.Owner property. There doesn't need to be an object that owns it; it could be a general subsystem of your program.)
Don't keep persistent references to objects you don't own. If you don't keep long-lived references to an object, then you don't have to worry about whether those references are still valid. The only persistent reference should be in the code that owns the object. Any other code that needs to use that object should receive a reference as an input parameter, use the object, and then discard the reference when it returns its result.
From what I am seeing, this code should always result in an error. FreeAndNil explicitly sets that passed value to Nil (aka 0), so you should absolutely get an access violation when trying to dereference the object.
Just to complicate the issue:
If the method you call is a static (not virtual) method and it does not call any virtual methods itself nor does it access any fields of the object, you will not get an access violation even if the object reference has been set to NIL.
The reason for this is that the access violation is caused by dereferencing the self pointer (in this case NIL), but that only happens when accessing a field or the object's VMT for calling a virtual method.
This is just an exception to the rule that you cannot call methods of an NIL object reference that I'd like to mention here.
If you set a pointer to nil, you shouldn't be able to use it any more. But if you have another pointer to the same object, you can use it without getting an AV, because this pointer still points to the object address and not to nil.
Moreover, freeing an object do not clear the memory used by the that object. It just marks it as not in use. Thats the reason you want get an AV. If the freed memory is allocated for another object, you will get a AV, because it no longer contains data that seems valid.
FastMM4 has some settings that you can use while debugging, that will detect such conditions. From the FsatMM4Options.inc:
{Set the following option to do extensive checking of all memory blocks. All
blocks are padded with both a header and trailer that are used to verify the
integrity of the heap. Freed blocks are also cleared to to ensure that they
cannot be reused after being freed. This option slows down memory operations
dramatically and should only be used to debug an application that is
overwriting memory or reusing freed pointers. Setting this option
automatically enables CheckHeapForCorruption and disables ASMVersion.
Very important: If you enable this option your application will require the
FastMM_FullDebugMode.dll library. If this library is not available you will
get an error on startup.}
{$define FullDebugMode}
Another quote from the same file:
FastMM always catches attempts to free the same memory block twice...
As delphi uses FastMM from Delphi 2007 (2006 ?), you should get an error if you try to doublefree an object.
Thomas Mueller: have you tried virtual class methods? A constructor is sort of a virtual method but you call it against the type - not the instance. This means that even some specific virtual methods will not cause AV on a null-reference :D
Vegar: You couldn't be more right! FastMM is the best ever ever ever tool that helped me tracking down this kind of bugs.
The EurekaLog Blog had a great post on this in April 2009:
Why should you always use FreeAndNil instead of Free.