【问题标题】:Is the implementation of Delphi interface reference counting future proofDelphi接口引用计数的实现是未来的证明吗
【发布时间】:2012-02-23 23:50:39
【问题描述】:

我有一个将在整个应用程序中广泛使用的辅助类。实现依赖于接口引用计数,大致思路是:

...
var
  lHelper: IMyHelper;
begin
  lHelper := TMyHelper.Create(some params);
  ...some code that doesn't have to access lHelper
end;

所以实现依赖于 IMyHelper 在方法结束时超出范围,而不是之前。

所以我要问的是,如果在其余方法中未访问变量,我能否确定在某些未来 Delphi 编译器不会发挥智能并在创建接口后立即释放接口?

【问题讨论】:

  • this blog post 的 cmets 可能会让您感兴趣。
  • 没有人可以确定未来,但问题下的编译器行为应该被认为是极不可能和不可取的。
  • 担心未使用的实例有什么意义?
  • 我在这里问了一个类似的问题:stackoverflow.com/questions/7759081/…
  • @mjn 这就是our profiling feature in our logging class的用途:在方法开头写TSynLog.Enter;会自动分析它,并在函数TSynLog返回的接口时生成一个“离开”日志条目.输入。

标签: delphi interface implementation reference-counting


【解决方案1】:

恕我直言,您可以对此充满信心。对于此方法的指令块,超出范围的模式可能会保持全局。这将是一个重大变化。

this comment from Barry Kelly(来自Embarcadero):

至于您之前关于显式变量的评论:在假设(和重大更改)的情况下,我们优化了接口变量的使用,我们可能不仅会破坏所描述的类似 RAII 的功能,而且还会破坏显式变量方法;分配给 FooNotifier 和 BarNotifier 的值没有被使用,因此“理论上”它们可以更快地被释放,甚至可能重用相同的存储空间。

当然,界面的破坏可能会产生副作用,这就是帖子中所依赖的效果。更改语言以使诸如此类的副作用具有可见的变化并不是我们愿意做的事情。

因此您可以猜到 Embarcadero 不会在此处引入任何向后兼容性更改。重用接口内存的好处不值得破坏兼容性和引入副作用:现在保存指针(4 或 8 个字节)是不值得的,特别是当堆栈已经分配并对齐时(x64 模型使用比 x86 更多的堆栈)。

只有在语言中引入垃圾收集器(从我个人的角度来看,我不希望这样做),对象的生命周期可能会改变。但在这种情况下,使用寿命可能会更长。

在所有情况下,您都可以创建自己的代码,以确保它会在方法结束时发布:

var
  lHelper: IMyHelper;
begin
  lHelper := TMyHelper.Create(some params);
  try 
    ...some code that doesn't have to access lHelper
  finally
    lHelper := nil; // release the interface count by yourself
  end;
end;

其实这是编译器已经生成的代码。写这个完全是多余的,但它会确保编译器不会欺骗你。

在谈到接口和引用计数时,请考虑 Delphi 中潜在的循环引用问题。请参阅this great article (i.e. "Example 2-15"),了解接口循环引用需要“弱指针”。

其他语言(如 Java 或 C#)使用垃圾收集器来解决此问题。 Objective C 使用显式的“归零弱指针”机制来解决它 - 参见 this discussionthis SO answer for a potential implementation。也许未来版本的 Delphi 可能会考虑使用类似于 Objective C 中引入的 ARC 模型的实现。但我怀疑会有明确的语法来保持与现有代码的兼容性。

【讨论】:

  • 这个想法是为了避免必须写try..finally,实际上在这种情况下我认为不需要它,lHelper := nil 就足够了,如果有异常然后它将退出范围并释放接口。话虽如此,我也不想写 lHepler := nil。
  • @DanielMaurić 你不需要。当前的语言指南声明它将在范围结束时被销毁。没有人能保证任何事情的未来。哎呀,他们可以将开始/结束更改为开始/结束,但这不太可能。
  • 我们可以肯定地说,如果要完成这样的更改,将阻止许多人每次升级他们的代码库,并且会扼杀产品销售,因此不会发生。
  • @Warren:有些人会将 Unicode 开关放在同一类别中。
  • 这是一个人们认为是个好主意的开关示例,直到他们体验到现实,即它会造成无法恢复的混乱,并且会杀死德尔福完全地。当客户是白痴时,工程师不应该听他们的客户,这证明了RAD Studio产品中的工程团队不会被一群相信“客户永远是对的”的MBA和西装的白痴所推翻。跨度>
【解决方案2】:

documentation 这么说(强调我的):

在 Win32 平台上,接口引用通常通过引用计数来管理,这取决于从 System/IInterface 继承的 _AddRef 和 _Release 方法。使用引用计数的默认实现,当一个对象仅通过接口被引用时,无需手动销毁;该对象在对它的最后一个引用超出范围时自动销毁

局部变量的作用域是方法,所以当前的规范是_Release在方法完成之前不会被调用。

从来没有承诺将来不会更改规范,但我认为对这部分语言进行更改的可能性微乎其微。

【讨论】:

    猜你喜欢
    • 2014-05-04
    • 2014-04-07
    • 1970-01-01
    • 1970-01-01
    • 2010-10-19
    • 2013-04-19
    • 2021-08-17
    • 1970-01-01
    • 2015-05-26
    相关资源
    最近更新 更多