4 Stimmen

Schnittstellen-"Rekursion" und Referenzzählung

Ich habe ein kleines Problem mit Schnittstellen. Hier ist es in Pseudo-Code:

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;

Kann jemand den Fehler erkennen? Ich brauche das Kind, um einen Verweis auf seine Eltern zu haben, aber die Referenzzählung funktioniert in dieser Situation nicht. Wenn ich eine ParentClass-Instanz erstelle und ein Kind hinzufüge, wird die Elternklasse nie freigegeben. Ich kann sehen, warum. Wie kann ich das Problem umgehen?

10voto

Barry Kelly Punkte 40566

Eine referenzgezählte Referenz hat eine doppelte Semantik: Sie fungiert sowohl als Eigentumsanteil als auch als Mittel zur Navigation im Objektgraphen.

Normalerweise brauchen Sie nicht beide dieser Semantik auf alle Verbindungen in einem Zyklus im Graph der Referenzen. Vielleicht haben nur die Eltern eigene Kinder und nicht andersherum? Wenn das der Fall ist, können Sie die Verweise der Kinder auf die Eltern zu schwache Verbindungen indem man sie als Zeiger speichert, etwa so:

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;

Dies ist sicher, wenn die Wurzel des Baums der Instanzen garantiert irgendwo erhalten bleibt, d.h. Sie verlassen sich nicht darauf, dass Sie nur einen Verweis auf einen Zweig des Baums behalten und trotzdem in der Lage sind, den gesamten Baum zu navigieren.

3voto

gabr Punkte 26255

Nun, die Referenzzählung natürlich tut in dieser Situation funktionieren - es löst das Problem nur nicht.

Das ist das größte Problem bei der Referenzzählung - wenn man eine zirkuläre Referenz hat, muss man sie explizit "unterbrechen" (z. B. eine Schnittstellenreferenz auf "null" setzen). Das ist auch der Grund, warum die Referenzzählung kein wirklicher Ersatz für die Garbage Collection ist - Garbage Collectors wissen, dass es Zyklen geben kann und können solche zyklischen Strukturen freigeben, wenn sie nicht von "außen" referenziert werden.

1voto

Lasse V. Karlsen Punkte 364542

Sie müssen eine Methode entwickeln, die explizit die richtigen Verweise aufhebt. Es gibt keine Möglichkeit, die automatische Zählung der Verweise in diesem Fall ordnungsgemäß funktionieren zu lassen.

0voto

RS Conley Punkte 7136

Bei der Verwendung eines Funktionszeigers im ersten Beispiel gibt es das Problem der zyklischen Verweise nicht. .NET verwendet Delegaten und VB6 verwendet Ereignisse. Diese haben alle den Vorteil, dass sie die Anzahl der Verweise auf das Objekt, auf das verwiesen wird, nicht erhöhen.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X