Ian*_*oyd 13 delphi const interface
我最近(再次)遇到Delphi编译器代码生成错误,当传递接口const
泄漏引用时.
如果声明您的方法传递接口变量const
,则会发生这种情况,例如:
procedure Frob(const Grob: IGrobber);
Run Code Online (Sandbox Code Playgroud)
并修复是简单地删除const
:
procedure Frob(Grob: IGrobber);
Run Code Online (Sandbox Code Playgroud)
我理解const
(和var
,和out
)允许您通过引用传递项目.在结构的情况下,这保存了参数副本; 让你只需将指针传递给项目.
在的情况下Object
/ Pointer
/ Interface
没有必要通过引用传递,因为它是一个引用; 它已经适合注册.
为了永远不再遇到这个问题,我进行了一次十字军东征.我搜索了所有源代码树:
const [A-Za-z]+\: I[A-Z]
Run Code Online (Sandbox Code Playgroud)
我删除了大约150个实例,我将接口作为const传递.
但有一些我无法改变.该TWebBrowser
回调事件被声明为:
OnDocumentComplete(Sender: TObject; const pDisp: IDispatch; var URL: OleVariant);
\___/
|
?
Run Code Online (Sandbox Code Playgroud)
我走得太远了吗?我做了一件坏事吗?
编辑:或者,用一个较少"基于意见"的风格问题来表达它:是否有任何严重的缺点,不能将接口作为const传递?
额外奖励:当Delphi没有(总是)增加接口引用计数时,它们违反了COM规则:
参考计数规则
规则1: 必须为接口指针的每个新副本调用AddRef,并且每次销毁接口指针都会调用Release,除非后续规则明确允许.
规则2:关于接口指针的两个或多个副本的生命周期的开始和结束的关系的一段代码的特殊知识可以允许省略AddRef/Release对.
因此,虽然它可能是编译器可以利用的优化,但它必须正确地执行以便不违反规则.
Dav*_*nan 16
如果声明您的方法将接口变量作为const传递,例如:
Run Code Online (Sandbox Code Playgroud)procedure Frob(const Grob: IGrobber);
那不太对劲.为了存在泄漏,您需要在代码中没有任何内容可以引用新创建的对象.所以,如果你写:
Frob(grob);
Run Code Online (Sandbox Code Playgroud)
那里没有问题,因为界面grob
已经至少有一个参考.
你写的时候会出现问题:
Frob(TGrobberImplementer.Create);
Run Code Online (Sandbox Code Playgroud)
在那种情况下,没有任何参考接口,所以它被泄露.好吧,只要实现中的任何内容都没有Frob
引用它,它就会被泄露.
我做了一件坏事吗?
嗯,这取决于.我认为你所做的一切都不会特别糟糕.在性能方面存在缺点,因为接受接口参数的所有函数现在都必须使用隐式try/finally块添加和释放引用.只有你能判断这是否重要.
更重要的问题与您无法控制的代码有关.你给
procedure OnDocumentComplete(Sender: TObject; const pDisp: IDispatch; var URL: OleVariant);
Run Code Online (Sandbox Code Playgroud)
举个例子.那里没有问题,因为你从不称呼那种方法.它是您实现的事件处理程序.框架调用它,并传递已经引用的接口.
真正的问题来自RTL中声明的方法或您调用的任何其他第三方代码.如果您正在调用方法,并且如果它们使用const
接口参数,那么您可能会陷入陷阱.
这很容易解决,尽管很烦人.
grob := TGrobberImplementer.Create;
Frob(grob);
Run Code Online (Sandbox Code Playgroud)
我处理这个问题的理由是这样的:
const
至少在某些时候处理调用接口参数.const
.