Recently, I came across some behavior that I simply could not and cannot explain related to Delphi interface variables.
Essentially, it comes down to the implicit interface variable that the compiler generates in the Broadcast method.
At the end of the instruction that completes the method, the epilogue code contains two IntfClear . One of which I can explain, it corresponds to the local variable Listener . Another that I canβt explain, and it will take you to TComponent._Release (Debug DCU) after destroying the instance of the object. This does not lead to AV, but it is just lucky, and with full debugging FastMM reports instance access after destruction.
Here is the code:
program UnexpectedImplicitInterfaceVariable; {$APPTYPE CONSOLE} uses SysUtils, Classes; type IListener = interface ['{6D905909-98F6-442A-974F-9BF5D381108E}'] procedure HandleMessage(Msg: Integer); end; TListener = class(TComponent, IListener) //TComponent._AddRef and TComponent_Release return -1 private procedure HandleMessage(Msg: Integer); end; { TListener } procedure TListener.HandleMessage(Msg: Integer); begin end; type TBroadcaster = class private FListeners: IInterfaceList; FListener: TListener; public constructor Create; procedure Broadcast(Msg: Integer); end; constructor TBroadcaster.Create; begin inherited; FListeners := TInterfaceList.Create; FListener := TListener.Create(nil); FListeners.Add(FListener); end; procedure TBroadcaster.Broadcast(Msg: Integer); var i: Integer; Listener: IListener; begin for i := 0 to FListeners.Count-1 do begin Listener := FListeners[i] as IListener; Listener.HandleMessage(Msg); end; Listener := nil; FListeners.Clear; FreeAndNil(FListener); end;//method epilogue: why is there a call to IntfClear and then TComponent._Release? begin with TBroadcaster.Create do begin Broadcast(42); Free; end; end.
And here is the analysis of the epilogue:

There, clear as day, are two calls to IntfClear.
So who can see the obvious explanation that I am missing?
UPDATE
Well, Uwe got it right away. FListeners[i] requires a temporary implicit variable for its result variable. I have not seen this since I assigned Listener , but, of course, another variable.
The next option is an explicit representation of what the compiler generates for my source code.
procedure TBroadcaster.Broadcast(Msg: Integer); var i: Integer; Intf: IInterface; Listener: IListener; begin for i := 0 to FListeners.Count-1 do begin Intf := FListeners[i]; Listener := Intf as IListener; Listener.HandleMessage(Msg); end; Listener := nil; FListeners.Clear; FreeAndNil(FListener); end;
When writing this method, it is obvious that Intf cannot be cleared to epilogue.
interface delphi
David Heffernan Mar 18 2018-11-18T00: 00Z
source share