【问题标题】:Interface "recursion" and reference counting接口“递归”和引用计数
【发布时间】:2010-09-15 08:43:51
【问题描述】:

我在接口上有一个小问题。这是伪代码:

type
  Interface1 = interface
  end;

  Interface2 = interface
  end;

  TParentClass = class(TInterfacedObject, Interface1)
  private
    fChild : Interface2;
  public
    procedure AddChild(aChild : Interface2);
  end;

  TChildClass = class(TInterfacedObject, Interface2)
  private
    fParent : Interface2;
  public
    constructor Create(aPArent : Interface1);
  end;

任何人都可以看到缺陷吗?我需要孩子引用它的父母,但在这种情况下引用计数不起作用。如果我创建一个 ParentClass 实例并添加一个子类,则永远不会释放父类。我明白为什么了。如何绕过它?

【问题讨论】:

标签: delphi oop interface


【解决方案1】:

您必须创建一个明确取消链接正确引用的方法。在这种情况下,无法让自动引用计数正常工作。

【讨论】:

  • 不需要显式方法;这取决于引用所需的语义。
【解决方案2】:

好吧,在这种情况下,引用计数当然确实起作用 - 它只是不能解决问题。

这是引用计数的最大问题——当你有一个循环引用时,你必须明确地“打破”它(例如,将一个接口引用设置为“nil”)。这也是为什么引用计数不能真正替代垃圾收集的原因——垃圾收集器知道循环可能存在,并且当它们没有从“外部”引用时可以释放这种循环结构。

【讨论】:

  • -1:“在这种情况下,引用计数当然可以工作”。废话。
【解决方案3】:

引用计数引用有两种语义:它充当所有权共享以及导航对象图的一种方式。

通常,您不需要在引用图中的循环中的所有链接上同时使用这两种语义。也许只有父母拥有孩子,而不是相反?如果是这种情况,您可以通过将它们存储为指针来使子引用父 弱链接,如下所示:

TChildClass = class(TInterfacedObject, Interface2)
private
  fParent : Pointer;
  function GetParent: Interface1;
public
  constructor Create(aPArent : Interface1);
  property Parent: Interface1 read GetParent;
end;

function TChildClass.GetParent: Interface1;
begin
  Result := Interface1(fParent);
end;

constructor TChildClass.Create(AParent: Interface1);
begin
  fParent := Pointer(AParent);
end;

如果保证实例树的根在某处保持活动状态,这是安全的,也就是说,您不仅仅依赖于保持对树分支的引用并且仍然能够导航整个树。

【讨论】:

    【解决方案4】:

    在第一个示例中使用函数指针,则不存在循环引用问题。 .NET 使用委托,而 VB6 使用事件。所有这些都具有不增加被指向对象的引用计数的好处。

    【讨论】:

      猜你喜欢
      • 2017-07-14
      • 1970-01-01
      • 2014-12-05
      • 2014-05-04
      • 2010-10-27
      • 1970-01-01
      • 2013-08-11
      • 2011-05-18
      • 1970-01-01
      相关资源
      最近更新 更多