Интерфейс «рекурсия» и подсчет ссылок - PullRequest
4 голосов
/ 05 октября 2008

У меня небольшая проблема с интерфейсами. Вот это в псевдокоде:

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 и добавляю дочерний элемент, родительский класс никогда не освобождается. Я понимаю почему. Как мне обойти это?

Ответы [ 4 ]

10 голосов
/ 05 октября 2008

Ссылка с подсчетом ссылок имеет две семантики: она действует как доля владения, а также как средство навигации по графу объектов.

Как правило, вам не нужно обе этой семантики для всех ссылок в цикле в графе ссылок. Может быть, только родители имеют детей, а не наоборот? В этом случае вы можете сделать дочерние ссылки на родительские слабые ссылки , сохранив их как указатели, например:

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;

Это безопасно, если корень дерева экземпляров гарантированно где-то сохраняется, т. Е. Вы не полагаетесь только на то, что сохраняете ссылку на ветку дерева и все еще можете перемещаться по нему целиком. 1010 *

3 голосов
/ 05 октября 2008

Ну, подсчет ссылок, конечно, работает в этой ситуации - просто не решает проблему.

Это самая большая проблема с подсчетом ссылок - когда у вас есть циклическая ссылка, вы должны явно «сломать» ее (например, установить одну ссылку интерфейса на «nil»). Вот почему подсчет ссылок на самом деле не является заменой для сборки мусора - сборщики мусора знают, что циклы могут существовать, и могут освобождать такие циклические структуры, когда на них нет ссылок извне.

1 голос
/ 05 октября 2008

Вы должны создать метод, который явно отменяет связь с правильными ссылками. В этом случае невозможно заставить работать автоматический подсчет ссылок.

0 голосов
/ 06 октября 2008

При использовании указателя на функцию в первом примере проблема циклических ссылок не существует. .NET использует делегатов, а VB6 использует события. Все они имеют преимущество, заключающееся в том, что они не увеличивают счетчик ссылок на указываемый объект.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...