delphi – 意外的隐式接口变量的神秘案例
发布时间:2020-12-15 03:51:56 所属栏目:大数据 来源:网络整理
导读:我最近遇到了一些我无法解释的行为,与Delphi接口变量有关. 从本质上讲,它归结为编译器在Broadcast方法中生成的隐式接口变量. 在终止方法的结束语句中,结尾代码包含对IntfClear的两次调用.其中一个我可以解释,它对应于Listener局部变量.另一个我无法解释,它会
我最近遇到了一些我无法解释的行为,与Delphi接口变量有关.
从本质上讲,它归结为编译器在Broadcast方法中生成的隐式接口变量. 在终止方法的结束语句中,结尾代码包含对IntfClear的两次调用.其中一个我可以解释,它对应于Listener局部变量.另一个我无法解释,它会在对象实例被销毁后将你带到TComponent._Release(Debug DCUs).它不会产生AV,但这很幸运,并且通过完整的FastMM调试,报告了破坏后实例访问. 这是代码: 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. 以下是结语的反汇编: 在那里,明确的是对IntfClear的两次调用. 那么,谁可以看到我遗漏的明显解释? UPDATE 好吧,Uwe马上得到它. FListeners [i]的结果变量需要一个临时隐式变量.我没有看到,因为我分配给Listener,但当然这是一个不同的变量. 以下变体是编译器为原始代码生成的内容的显式表示. 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; 当以这种方式书写时,显然Intf无法在结尾之前被清除. 解决方法
只是一个猜测,但也许作为IListener的FListeners [i]使用FListeners [i]的临时变量.毕竟它是函数调用的结果.
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |