8

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

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

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

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

4

2 回答 2

10

IMHO you can be confident of that. The out-of-scope pattern will probably remain global to the instruction block of this method. This would be a breaking change.

See this comment from Barry Kelly (from Embarcadero):

As to your earlier comment, about explicit variables: in the hypothetical (and breaking change) case, where we optimized interface variable usage, we would likely not only break the described RAII-like functionality but also the explicit variable approach too; the values assigned to FooNotifier and BarNotifier are not used, so "in theory" they can be freed up sooner, and potentially even reuse the same storage.

But of course, destruction of the interface can have side-effects, and that's what's being relied upon for the effect in the post. Changing the language such that side-effects like these have visible changes is not something we do willingly.

So you can guess that Embarcadero won't introduce any backward compatibility change here. The benefit of re-using an interface memory won't be worth breaking compatibility and introducing side effects: saving a pointer (4 or 8 bytes) is not worth it nowadays, especially when the stack is already allocated, and aligned (x64 model uses more stack than x86).

Only if a Garbage Collector is introduced to the language (which I do not want from my personal point of view), objects life time may change. But in this case, life time may probably be longer.

In all cases, you can create your own code, to be sure that it will released at the end of the method:

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;

In fact, this is the code already generated by the compiler. Writing this will be perfectly redundant, but it will ensure that compiler won't cheat on you.

When speaking of interfaces and reference counting, please take in account the potential issue of circular references in Delphi. See this great article (i.e. "Example 2-15") about the need of "weak pointers" for circular references of Interfaces.

Other languages (like Java or C#) use a garbage collector to resolve this. Objective C uses an explicit "zeroing weak pointers" mechanism to solve it - see this discussion or this SO answer for a potential implementation. Perhaps future version of Delphi may consider using an implementation similar to the ARC model introduced in Objective C. But I suspect there will be an explicit syntax to preserve compatibility with existing code.

于 2012-02-01T09:50:57.323 回答
4

文档说明了这一点(强调我的):

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

局部变量的范围是方法,因此当前规范是_Release在方法完成之前不会调用它。

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

于 2012-02-01T09:54:42.350 回答