I know of these three techniques:
Manually
uses System.Classes; procedure DoSomething; var sl: TStringList; begin sl := TStringList.Create; try finally sl.Free; // Invoking destructor end; end;
Reference counting / interface (
Fastest example from the top of my head in the standard library:TInterfacedObject
)uses Xml.XMLDoc, Xml.XMLIntf; procedure DoSomething; var xmldoc: IXMLDocument; begin xmldoc := TXMLDocument.Create(nil) as IXMLDocument; end; // No reference to xmldoc anymore, freed automatically
Ownership
Like almost the whole VCLibrary or this one:uses System.Generics.Collections; procedure DoSomething; var ol: TObjectList<TObject>; i: Integer; o: TObject; begin ol := TObjectList<TObject>.Create(true); // the list takes ownership of the objects try for i := 0 to 9 do begin o := TObject.Create; ol.Add(o); end; finally ol.Free; // does not only free the list but all objects in the list, too end; end;
Are there more?
CodePudding user response:
When it comes to memory management models for managing object instances in Delphi, there are two: manual memory management and automatic reference counting. All object instances will be released either manually or through reference counting mechanism.
But when it comes to actual coding patterns, there is number of ways we can write the code in order to trigger the release of an object instance and it is almost impossible to list and categorize them all.
The best way to illustrate the complexity involved is by asking additional question:
What do you consider as a memory management technique?
For instance, manually releasing object instance requires invoking the destructor. But there are several commonly used ways to do so: by calling Free
, Destroy
, or FreeAndNil
. But, Free
and FreeAndNil
eventually will call Destroy
. So the question is, should we consider that those different methods of invoking the destructor are the same technique or different techniques? What about other custom written methods that will trigger destruction of an object instance?
When it comes to releasing reference counted object instance, your example has shown indirect way of release - just letting reference go out of scope. But there is an additional way to release such object instance, and that is by explicitly assigning nil
to such reference.
procedure DoSomething;
var
xmldoc: IXMLDocument;
begin
xmldoc := TXMLDocument.Create(nil) as IXMLDocument;
...
xmldoc := nil;
...
end;
Again, the question is whether we consider those two different examples as the same or different?
When it comes to ownership, it is just a way to delegate releasing an object instance to some other entity. At the end, in case of manually managed object instances some code at some point will directly invoke destructor on such object. While this is clearly a different coding pattern than directly invoking destructor on object reference without going through additional layers of indirection, at the end the instance will be released manually.
We can also transfer ownership of reference counted object instances. If you have a collection that holds interface references, then this can also be considered as ownership transfer, as release of those instances will depend on the release of the collection itself, even though involved code will not directly call destructor, but will rely on automatic reference counting to do so.
The next question that arises is: What about fields? Your first example shows construction and destruction of local object instance. If we have an object field in a class and manually call Free
to such field in its destructor, should we consider that as a manual technique or ownership transfer, because actual release of that inner object instance will depend on the release of its outer, owning object.
There is additional aspect to reference counting. While compiler automatically inserts reference counting code (calls to _AddRef
and _Release
methods) in appropriate places, the _Release
method itself will have to directly call the destructor to actually free the instance. In a way this is just another example of ownership transfer, with some help of the compiler.
From one perspective, we can say that those three techniques you have mentioned are the (two) three basic techniques to release an object instance. But one the other hand, there is an infinite number of them.