What does the Free() method actually do internally and how does it handle object references? - delphi

Question
In the code below a new object of type TStringList is created and passed to a procedure which is using that object. By passing the object to the method ProcToFillStringList a new object reference is created by coping the reference. My questions regarding this code are:
What happens to the object reference stored in the parameter SList
after the method returns? Does it remove the reference to the object
from the stack?
What does the Free() method actually do internally? Does it remove all references to the object from the stack or does it remove
the object itself? Which references are removed?
Do object references (not the object itself) get removed from stack automatically when a method returns?
Would it be better to pass the reference byref?
Code
var
SL: TStringList; // first object reference
begin
SL := TStringList.Create; // creating object
try
ProcToFillStringList(SL);
finally
SL.Free; // -> what gets 'freed' here? the object? the references? both?
end;
end;
procedure ProcToFillStringList(const SList: TStrings); // second object reference
SList.Add('x'); // not calling Free -> does the reference get removed?
end;

Here is code of Free method on newer versions of Delphi:
procedure TObject.Free;
begin
// under ARC, this method isn't actually called since the compiler translates
// the call to be a mere nil assignment to the instance variable, which then calls _InstClear
{$IFNDEF AUTOREFCOUNT}
if Self <> nil then
Destroy;
{$ENDIF}
end;
There are two different cases. When compiled to environment with automatic reference counting (that is iOS), Free doesn't work at all, objects are freed only when the last reference to them is removed (but as said in comments to code above, compiler changes your SL.Free to SL:=nil, so if it was the last reference to object, it will be freed and SL is really set to nil.
But in all other platforms objects are not reference counted. When calling Free, object memory is freed, but your variable is not set automatically to nil (not saying about another variables pointing to the same object), that's just impossible with syntax like this. Any method of object can't change variable it's called from. That's why you write SL := TStringList.Create instead of SL.Create. In first case you get new memory address where object is created and assign SL to it. In second SL is not initialized and can point anywhere, so there is no way to create object exactly there.
So, to answer your questions:
Object reference in local procedure is removed when it goes beyond the scope. But if you use const or var argument, it is not created in the first place. Actually, you're using the same reference SL here.
In iOS Free does nothing, object will be destroyed automatically when SL variable goes beyond the scope. In other platforms, Free destroys object and doesn't affect other references at all.
Yes, they do.
Use that modifier which describes your situation best. Const will tell compiler and people working with your code (including yourself) that argument won't be changed in procedure, compiler may pass it by value (for objects less than pointer) or by reference, but no matter what it chooses, refcount will never be increased, so from this point of view, you can think that you use exactly the same object, like it was passed by reference.
Using Var (by reference) you can accidentally change the variable you passed to procedure and this makes your intentions unclear, so use it only when you really want to change this variable and Const otherwise.

In the documentation of embarcadero is written
System::TObject::Free automatically calls the destructor if the object reference is not nil
It means in your case that the object SL is cleared at the point you called SL.Free. A object inherited from TObject does not know how many references are alive to that instance. Only the pointer to the address of the instance of SL is passed to the function call ProcToFillStringList. The instance is not informed about the new reference.
If you want to handle reference counting have a look at TInterfacedObject and the 3 Methods
QueryInterface
_AddRef
_Release

a new object reference is created by coping the reference
New reference const SList is just non-changeable pointer to the object. It will be removed from the stack if it lives there (in this case parameter is passed through register).
Free doesn't clear any references. It just destructs an object, frees it's memory. There is 'FreeAndNil' routine that frees object and makes one reference nil. Other references still exist.

Related

Is this a bug in System.Net.HttpClient on Rio?

This is the function found in Delphi Rio in System.Net.HttpClient
THTTPClientHelper = class helper for THTTPClient
....
procedure THTTPClientHelper.SetExt(const Value);
var
{$IFDEF AUTOREFCOUNT}
LRelease: Boolean;
{$ENDIF}
LExt: THTTPClientExt;
begin
if FHTTPClientList = nil then
Exit;
TMonitor.Enter(FHTTPClientList);
try
{$IFDEF AUTOREFCOUNT}
LRelease := not FHTTPClientList.ContainsKey(Self);
{$ENDIF}
LExt := THTTPClientExt(Value);
FHTTPClientList.AddOrSetValue(Self, LExt);
{$IFDEF AUTOREFCOUNT}
if LRelease then __ObjRelease;
{$ENDIF}
finally
TMonitor.Exit(FHTTPClientList);
end;
end;
What the guy try to do with LRelease here?
{$IFDEF AUTOREFCOUNT}
LRelease := not FHTTPClientList.ContainsKey(Self);
{$ENDIF}
LExt := THTTPClientExt(Value);
FHTTPClientList.AddOrSetValue(Self, LExt);
{$IFDEF AUTOREFCOUNT}
if LRelease then __ObjRelease;
{$ENDIF}
So if FHTTPClientList doesn't contain the THTTPClient add it in the FHTTPClientList and then reduce it's refcount by one. Why reduce it's refcount by one?? the THTTPClient is still alive and used why breaking it's refcount? Their is a bug here, maybe the guy make a typo, but i don't understand what he want to do originally ...
for info this this how items are removing from the dictionary :
procedure THTTPClientHelper.RemoveExt;
begin
if FHTTPClientList = nil then
Exit;
TMonitor.Enter(FHTTPClientList);
try
FHTTPClientList.Remove(Self);
finally
TMonitor.Exit(FHTTPClientList);
end;
end;
Purpose of the manual reference counting for ARC compiler in above code is simulating dictionary with weak references. Delphi generic collections are backed with generic arrays that will hold strong reference to any object added to the collection on ARC compiler.
There is several ways to achieve weak references - using pointers, using wrappers around object where object is declared as weak and manual reference counting in appropriate places.
With pointers you lose type safety, wrappers require significantly more code, so I guess the author of above code opted for manual reference counting. Nothing wrong with that part.
However, as you noticed, there is something fishy in that code - while SetExt routine is written properly RemoveExt has a bug resulting in a crash later on.
Let's go through the code in context on ARC compiler (I will omit compiler directives and unrelated code for brevity):
Since adding object into collection (array) increases reference count, to achieve weak reference we have to decrease reference count of the added object instance - that way the instance's reference count will remain the same after it is stored in collection. Next, when we remove object from such collection, we have to restore reference count balance and increase reference count. Also we have to make sure that object will be removed from such collection before it is destroyed - good place to do that is destructor.
Adding to collection:
LRelease := not FHTTPClientList.ContainsKey(Self);
FHTTPClientList.AddOrSetValue(Self, LExt);
if LRelease then __ObjRelease;
We add the object to the collection and then after collection holds strong reference to our object we can release it's reference count. If object is already inside collection that means it's reference count was already decreased and we must not decrease it again - that is the purpose of LRelease flag.
Removing from collection:
if FHTTPClientList.ContainsKey(Self) then
begin
__ObjAddRef;
FHTTPClientList.Remove(Self);
end;
If object is in collection we have to restore the balance and increase the reference count before removing object from collection. This is the part that is missing from RemoveExt method.
Making sure that object is not in the list upon destruction:
destructor THTTPClient.Destroy;
begin
RemoveExt;
inherited;
end;
Note: In order for such faked weak collection to work properly items must be added and removed only through above methods that take care of balancing reference count. Using any other original collection methods like Clear will result in broken reference count.
Bug or not?
In System.Net.HttpClient code broken RemoveExt method is called only in destructor, also FHTTPClientList is private variable and it is not altered in any other way. On the first glimpse, that code works properly, but actually contains rather subtle bug.
To unravel the real bug we need to cover possible usage scenarios, starting with few established facts:
Only methods that alter content and by that reference count of items in FHTTPClientList dictionary are SetExt and RemoveExt methods
SetExt method is correct
Broken RemoveExt method that does not call __ObjAddRef is called only in THTTPClient destructor and this is where this subtle bug originates.
When destructor is called upon any particular object instance that means object instance has reached it's lifetime, and any subsequent reference counting triggers (during destructor execution) have no influence on the code correctness.
That is ensured by applying objDestroyingFlag on FRefCount variable changing its value and any further count increasing/decreasing can no longer result in special value 0 that starts destruction process - so object is safe and will not get destroyed twice.
In above code when THTTPClient destructor is called that means last strong reference to object instance has gone out of scope or was set to nil and at that moment the only remaining live reference that can trigger reference counting mechanism is the one in FHTTPClientList. That reference has been cleared by RemoveExt method (broken or not) at that point as previously said it does not matter. And everything works fine.
But, author of the code has forgotten one tiny weeny thingy - DisposeOf method that triggers the destructor, but at that point object instance has not reached its reference counting lifetime. In other words - if destructor is called by DisposeOf, any subsequent reference counting triggers must be balanced because there are still live references to the object that will trigger reference counting mechanism after the destructor chain calls are completed. If we break the counting at that point result will be catastrophic.
Since THTTPClient is not TComponent descendant that requires DisposeOf it is easy to make the oversight and forget that someone, somewhere could call DipsoseOf on such variable anyway - for instance if you make owned list of THTTPClient instances clearing such list will call DisposeOf on them and happily break their reference count because RemoveExt method is ultimately broken.
Conclusion: Yes, it is a BUG.

Why does Assigned return true for uninitialized variables?

I read many posts on forum about pointers, Assigned function, Free function, FreeAndNil function, etc... I already know Free function don't remove the pointer reference to an object assigned and FreeAndNil does it... All posts I read treat this subject considering Create method already was executed, or in other words, considering an object already created.
My question is: Why Assigned function returns true for a uninitialized object variable ?
Follow an example:
procedure TForm1.FormCreate(Sender: TObject);
var
Qry: TADOQuery;
begin
if Assigned(Qry) then
ShowMessage('Assigned')
else
ShowMessage('Unassigned');
Qry := TADOQuery.Create(nil);
if Assigned(Qry) then
ShowMessage('Assigned')
else
ShowMessage('Unassigned');
end;
That example displays 'Assigned' twice!
Conclusion: Immediately after Qry has been declared and before its create method has been executed the pointer to Qry isn't NIL !
If I put Qry := nil; at the first line into procedure above everything works fine... it displays 'Unassigned' and 'Assigned'.
Why??
Is there any safe way to know if a class variable already has its create method executed?
Your variable is a local variable and so is not initialized. It could contain any value.
The documentation says:
On the Win32 platform, the contents of
a local variable are undefined until a value is assigned to
them.
Note that, as an implementation detail, some types are managed and even local variables of managed types are initialized. Examples of managed types include: strings, interfaces, dynamic arrays, anonymous types and variants.
You ask:
Is there any safe way to know if a class variable already has its create method executed?
If that variable is a local variable, the answer is no. The onus falls to you the programmer. In practice it is seldom an issue because good code has short procedures which makes it harder for you to slip up. And even if you do the compiler will invariably warn you.
Other types of variables like class fields and global variables are initialized.
Because when creating a pointer, it cames with whatever garbage value was in that memory position. If you want to write NIL in it, it takes some CPU cycles, and I think it's not automatically done by Delphi because you may want something faster. In your example, why assign NIL to a variable, if soon afterwards you're going to put another value in it?
From the documentation of the Assigned function (emphasis mine):
Use Assigned to determine whether the pointer or procedure referenced by P is nil. P must be a variable reference of a pointer or procedural type. Assigned(P) corresponds to the test P<> nil for a pointer variable, and #P <> nil for a procedural variable.
Assigned returns false if P is nil, true otherwise.
Note: Assigned can't detect a dangling pointer--that is, one that isn't nil but no longer points to valid data. For example, in the code example for Assigned, Assigned won't detect the fact that P isn't valid.
The Assigned function is effectively implemented as:
function Assigned(const P): Boolean;
begin
Result := Pointer(P) <> nil;
end;
So the function isn't really checking whether the value truly is assigned. Rather it's checking a side-effect of being assigned.
As a result the function is guaranteed to return True if it is assigned.
But behaviour is undefined if the value is uninitialised. Basically since an uninitialised value has a garbage value left over from previous operations, it might be nil, or if might not.
Another thing to note is that Assigned has no way to determine the validity of its value. E.g. The following call to Assigned returns True even though the underlying object is no longer valid.
var
LObject: TObject;
begin
LObject := TObject.Create;
LObject.Free;
if Assigned(LObject) then ShowMessage('Still assigned!?');
end;
EDIT: Addendum
In response to the second part of your question.
Is there any safe way to know if a class variable already has its create method executed?
There is no safe way to determine if an object instance has been created. (There's also no way to reliably confirm that it hasn't already been destroyed.)
However, there are conventions (and good practices) you can follow to help you on the way.
First note that you should only be "unsure" if something was created if it's a deliberate feature of that piece of code. E.g. If you intend an object to be "lazy initialised".
What I'm trying to say here is: Never check Assigned just because you're worried that there might be a bug that prevents it from being assigned.
Not only is this impossible to do reliably, but you overcomplicate your code... Which increases the chance of bugs.
Also if you find something is unexpectedly not Assigned, then what can you do about it? Ignoring it would simply be pointless. Also, it's no good saying: "Ok, then I'll create the object". Because then you're duplicating creation logic in multiple places.
Basically you should try to make every part of your program correct - not have your program try to double-check itself everywhere.
So now that we're (hopefully) agreed that you only check if something is created if you've deliberately chosen that being created is optional. You do this as follows:
At first opportunity, ensure the variable/field reference is initialised to nil. So then it's guranteed to be assigned a value which means the object is not created. (Yes, the naming is a bit warped.)
You can set the vairable/field reference to a new instance of an object or set it by copying another reference of an already existing object. (Note the existing refernce might also be nil, but that doesn't cause any problems.)
If you ever destroy the object (or even just want to stop using it from that reference), set your variable/field reference to nil again.
NOTE: Delphi already initialises the member fields of a new class. So those won't need special attention.

Do I need to Free IDispatch in Delphi

How to free IDispatch COM Object in Delphi? Do I have to?
type
IUtility = interface(IDispatch);
var
obj: IUtility;
begin
obj := CreateOleObject("Utility") as IUtility;
// doesnot work
VariantClear(obj);
end;
IDispatch is just like all other interfaces. When an object implementing it sees its reference count reach zero, it will destroy itself.
Delphi automatically inserts code to call _AddRef and _Release on interfaces at the appropriate times, including when a variable goes out of scope. Thus, at the end of your function, obj will go out of scope, and the compiler will automatically insert code to essentially do if not Assigned(obj) then obj._Release.
Since it happens automatically, you don't need to do anything yourself. However, if you want to relinquish control of an interfaced object earlier than the natural end of the scope, you can simply clear the variable by assigning nil.
obj := nil;
Your obj variable is not of type Variant, which is why it's wrong to call VariantClear on it.

Class doesn't work when defined as a global variable in delphi

I created a simple class to explain my problem:
ttest =class
private
val:boolean;
published
function get:boolean;
end;
...
function ttest.get: boolean;
begin
val:=not val;
result:=val;
end;
Now if I declare a local ttest variable and call my_var.get; then everything works, but if I declare it as a global variable then it can't access the val field anymore, it shows an error message which says "Access violation...".
I read some articles about classes in Delphi but still can't find my mistake.
You've neglected to instantiate the class.
Global class-reference variables are initialized to nil, whereas local variables are not initialized at all. The local variable has a value determined by whatever happened to be on the stack at the time you called your function, and your program is interpreting that value as though it were a TTest reference even though it's really not. Your program then reads the value at that memory address to get the value that would represent the val field.
The only reason your code appears to work with a non-global variable is luck. Whether it's good luck or bad is another matter. (Good luck, since your code appeared to work, and working code is always nice. Bad luck, since you'd have been alerted to your mistake earlier if your code had crashed.)
Instantiate a class before you use references to it.
x := TTest.Create;
Now you can access fields, methods, and properties of the object via the x variable.
You should have gotten a compiler warning when you attempted to use a local variable without assigning a value to it first. Although they're just warnings, and your program will still run, never ignore a warning or even a hint. When the compiler bothers to complain about something, it's usually right.
In Delphi object variables are always pointers. Before you can use the variable you need to initialize it with a reference to an object. The most common way to do that is to create a new object of the particular class.
procedure Foo;
var
Obj: TObject;
begin
Obj := TObject.Create;
try
// Do stuff with Obj
finally
Obj.Free;
end;
end;
In this case Obj starts out as an uninitialized pointer (it will point to random memory). It is only after we assign the newly created TObject that Obj is a valid object reference.
In Delphi there is no automatic garbage collection for objects, so you always need to call free on them when you are done using them. If you declare a global or local object variable, you can initialize it the special initialization section of the unit and free the object in the finalization section.
unit myunit;
interface
var
Obj: TObject;
implementation
initialization
Obj := TObject.Create;
finalization
Obj.Free;
end.
Variables declared in the interface section are globally visible, variables declared in the implementation section are only visible inside the unit. It should be noted that declaring a global object variable means that any unit can overwrite the variable with a reference to a new object without freeing the existing object first. This would cause a memory leak as again there is no automatic garbage collection.
A delphi class is basically just a description, not the object itself. You describe the properties and methods the final object should have. And the missing piece of the puzzle is that you havent really told Delphi to create an object from your class.
This is done by calling the constructor:
mMyInstance:=TTest.Create;
The constructor takes the class description and builds an object instance for you in memory. It returns a pointer to the object which you must store in a variable (myInstance in the above example) of the same type.
Reading your question, I suspect you want to create an object that is "always there", a bit like the printer object. This is easy to do, but just like the printer object - you must include that unit before you can access the object. I think Anders E. Andersen above has shown how most people would initialize an object from a unit centric point of view.
If you want the object to be reachable from another unit, say your mainform or any other unit, first add "myunit" to the uses list. Then to make it visible you add a function, like this:
function test:ttest;
Begin
result:=obj;
end;
And remember to add "function test:TTest" to the interface section of the unit. Then you can use the object from another unit as such:
myUnit.test.get;
But be warned! This is pretty old school programming, and you run the risk of your unit being released (which calls finalization and thus destroys your object) before the other units are done with it. Thus you risk calling a function in an object which no longer exists in memory - causing a spectacular access violation when your program closes.
If you want to learn Delphi properly, head over to Delphi Basics and read up on the basic principles. It takes a while to learn a new language but you will soon get the hang of it.
Good luck!

Delphi7, passing object's interface - causes Invalid Pointer Operation when freeing the object

I have a class that implements an interface, which is made available for plugins.
The declaration of class is quite simple. There is only one instance of this class for an entire application. When the function that returns the interface is called, it calls _AddRef on the retrieved interface before passing it back as result. Unfortunately it works until I try to free the object (see "finalization" section) - it reports Invalid Pointer Operation. If I comment it out, it works fine (however FastMM reports memory leaks, so the object is not being freed).
Here is the part of the code in the function that returns the interface (in fact it is an overridden QueryInterface of my "ServicesManager" class).
if ConfigManager.GetInterface(IID, obj) then
begin
ISDK_ConfigManager(obj)._AddRef;
result:= 0;
end
and the code of ConfigManager class ...
type
TConfigManager = class(TInterfacedObject, ISDK_ConfigManager)
private
...
end;
var
ConfigManager: TConfigManager;
implementation
...
initialization
ConfigManager:= TConfigManager.Create();
finalization
if ConfigManager <> nil then
FreeAndNil(ConfigManager); //if I comment it out, it leaks the memory but no Invalid Ptr. Op. raises
What am I doing wrong?
I need to pass a reference to exactly this instance of ConfigManager.
The number one piece of advice you'll hear when dealing with interfaces is to never mix interface references with object references. What this means is that once you start referring to an object via an interface reference, you cease to refer to it via an object reference. Ever.
The reason is that the first time you assign an interface variable, the reference count of the object will become 1. When that variable goes out of scope or gets assigned a new value, the reference count becomes zero, and the object frees itself. This is all without any modification of the original object-reference variable, so when you later try to use that variable, it's not a null pointer, but the object it referred to is gone — it's a dangling reference. When you try to free something that doesn't exist, you get an invalid-pointer-operation exception.
Declare your ConfigManager variable as an interface. Don't free it yourself. Once you do that, you can move the entire declaration of TConfigManager into the implementation section because no code outside that unit will ever refer to it.
Also, there's rarely any reason to provide your own implementation of QueryInterface. (You said you overrode it, but that's impossible since it's not virtual.) The one provided by TInterfacedObject should be sufficient. The one you're providing is actually causing a memory leak because you're incrementing the reference count when you shouldn't be. GetInterface already calls _AddRef (by performing an interface assignment), so you're returning objects with inflated reference counts.
You said this is a plugin system? Are you loading your plugins as BPLs? I ran into that problem last week, actually. You can't rely on finalization to clear your interface references. You need to make sure to clear them before you unload the plugin, or its memory space becomes invalid.
Edit: By "clearing interface references" I mean calling _Release on them, either by manually setting it to nil or by letting the references go out of scope. If your interface manager holds interface references to the plugins, they'll get cleared when the interface manager gets destroyed.
I totally agree with Rob.
What most likely helps is rewriting your initialization code like below.
Now ConfigManager is of type ISDK_ConfigManager, and by assigning nil to it, the reference count will decrement.
When the reference count becomes zero, it will automatically become freed.
type
TConfigManager = class(TInterfacedObject, ISDK_ConfigManager)
private
...
end;
var
ConfigManager: ISDK_ConfigManager;
implementation
...
initialization
ConfigManager:= TConfigManager.Create();
finalization
ConfigManager := nil;
end;
--jeroen
does TConfigManager class has any method declared as "published"?

Resources