gpt4 book ai didi

delphi - 我不应该将接口(interface)作为 const 传递吗?

转载 作者:行者123 更新时间:2023-12-03 14:37:46 28 4
gpt4 key购买 nike

我最近(再次)遇到the Delphi compiler code-gen bug when passing an interface as const泄漏引用。

如果您的方法被声明为将接口(interface)变量作为 const 传递,则会发生这种情况,例如:

procedure Frob(const Grob: IGrobber);

修复方法是简单地删除 const:

procedure Frob(Grob: IGrobber);

据我了解,const(以及 varout)允许您通过引用传递项目。对于结构体,这会保存参数副本;让您只需将指针传递给该项目即可。

对于对象/指针/接口(interface),不需要通过引用传递,因为它 引用;它已经适合寄存器了。

为了不再遇到这个问题,我进行了一次十字军东征。我搜索了所有源代码树:

const [A-Za-z]+\: I[A-Z]

我删除了大约 150 个将接口(interface)作为 const 传递的实例。

但有些是我无法改变的。 TWebBrowser 回调事件声明为:

OnDocumentComplete(Sender: TObject; const pDisp: IDispatch; var URL: OleVariant);
\___/
|
?

我是不是走得太远了?我是不是做了坏事?

编辑:或者,用不太“基于意见”风格的问题来表述:是否有任何严重的缺点> 将接口(interface)作为 const 传递?

奖励:当 Delphi 不(总是)增加接口(interface)引用计数时,它们就违反了 The Rules of COM :

Reference-Counting Rules

Rule 1: AddRef must be called for every new copy of an interface pointer, and Release called for every destruction of an interface pointer, except where subsequent rules explicitly permit otherwise.

Rule 2: Special knowledge on the part of a piece of code of the relationships of the beginnings and the endings of the lifetimes of two or more copies of an interface pointer can allow AddRef/Release pairs to be omitted.

因此,虽然这可能是编译器可以利用的优化,但它必须正确执行,以免违反规则。

最佳答案

This happens if your method is declared to pass an interface variable as const, e.g.:

procedure Frob(const Grob: IGrobber);

这不太正确。为了防止泄漏,您需要代码中没有任何内容引用新创建的对象。所以如果你写:

Frob(grob);

没有问题,因为接口(interface) grob 已经至少有一个引用。

当你这样写时就会出现问题:

Frob(TGrobberImplementer.Create);

在这种情况下,没有任何东西需要对接口(interface)的引用,因此它会被泄漏。好吧,只要 Frob 的实现中没有任何内容引用它,它就会被泄露。

Have I done a bad thing?

嗯,这要看情况。我不认为你所做的事情会带来什么特别糟糕的结果。性能方面存在缺点,因为所有接受接口(interface)参数的函数现在都必须使用隐式 try/finally block 添加和释放引用。只有你才能判断这是否重要。

更重要的问题与您无法控制的代码有关。你给

procedure OnDocumentComplete(Sender: TObject; const pDisp: IDispatch; var URL: OleVariant);

举个例子。那里没有问题,因为你从不调用该方法。它是您实现的事件处理程序。框架调用它,并且它传递一个已经引用的接口(interface)。

真正的问题来自于 RTL 中声明的方法或您调用的任何其他第三方代码。如果您正在调用这些方法,并且它们使用 const 接口(interface)参数,那么您可能会陷入陷阱。

虽然很烦人,但很容易解决。

grob := TGrobberImplementer.Create;
Frob(grob);

我处理这个问题的理由是这样的:

  1. 按值传递接口(interface)参数会产生性能成本。
  2. 我无法确保我调用的每个方法都会按值接受接口(interface)参数。
  3. 因此,我接受这样一个事实:至少在某些时候我需要处理调用 const 接口(interface)参数。
  4. 由于我有时必须处理它,并且由于我讨厌不一致,因此我选择一直处理它。
  5. 因此,我选择将我编写的方法中的所有接口(interface)参数设置为 const
  6. 因此,我确保永远不会将接口(interface)作为参数传递,除非它已被变量引用。

关于delphi - 我不应该将接口(interface)作为 const 传递吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31028266/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com