Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Delphi Intelligente Objekte - automatische Freigabe von Referenzen (https://www.delphipraxis.net/166899-intelligente-objekte-automatische-freigabe-von-referenzen.html)

Thom 5. Mär 2012 02:40

Intelligente Objekte - automatische Freigabe von Referenzen
 
Hiermit möchte ich ein Konzept zur automatischen Freigabe von Referenzen auf nicht mehr vorhandene Objekte zur Diskussion stellen.

Über das automatische Rücksetzen von Referenzen wurde schon viel diskutiert. Einer der Threads zu diesem Thema ist stahli's Referenzen auf ungültige Objekte.

Jedem ist (sollte) bekannt (sein), daß nach
Delphi-Quellcode:
var
  o1, o2: TObject;
begin
[...]
  o1:=TObject.Create;
  o2:=o1;
  o1.Free;
[...]
end;
Listing 1
sowohl o1 als auch o2 noch auf ein (nicht mehr gültiges) Objekt verweisen. Auch das verteufelte FreeAndNil schafft nur teilweise Abhilfe:
Delphi-Quellcode:
var
  o1, o2: TObject;
begin
[...]
  o1:=TObject.Create;
  o2:=o1;
  FreeAndNil(o1);
[...]
end;
Listing 2
In diesem Fall bleibt o2 erhalten, auch wenn o1 auf nil gesetzt wurde.

Obwohl es zu diesem Thema meistens negative Meinungen gibt (braucht man nicht, Blödsinn, zeugt von einem schlechten Design, ...), existieren Fälle, in denen das automatische Setzen von ungültigen Referenzen auf nil von entscheidender Bedeutung ist.

Dazu ein praktisches Beispiel mit dem Delphi Framework für Google Maps:
Delphi-Quellcode:
  TForm1 = class([...])
    [...]
  private
    FMyMarker: TMarker; //Stelle 1
    [...]
  end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  with Script do
  begin
    FMyMarker:=New(Google.Maps.Marker); //Stelle 2
    FMyMarker.Position:=New(Google.Maps.Point(10,20));
    FMyMarker.Map:=Maps[0];
  end;
end;
Listing 3
In der Methode Button1Click werden zwei Objekte neu erstellt: TMarker und TPoint. Der Marker wird an zwei Stellen gespeichert: In FMyMarker (Stelle 1) und - nicht offensichtlich - in der Marker-Liste des Script-Objektes, also TScript.Markers (Stelle 2). Zusätzlich melden sich beide Objekte in einer frameworkinternen Liste an, um Speicherlecks zu vermeiden. Das TPoint-Objekt wird so spätestens bei Beendigung des Programmes freigegeben.
Werden jetzt aber massenhaft neue Marker angelegt, steigt der Speicherverbrauch duch die Punkte, obwohl sie eigentlich gar nicht mehr benötigt werden. Abhilfe würde eine "ordentlichere" Programmierung im Delphi-Stil schaffen:
Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var
  Point: TPoint;
begin
  with Script do
  begin
    Point:=New(Google.Maps.Point(10,20));
    try
      FMyMarker:=New(Google.Maps.Marker);
      FMyMarker.Position:=Point;
      FMyMarker.Map:=Maps[0];
    finally
      Point.Free;
    end;
  end;
end;
Listing 4
Leider macht das den Quelltext nicht gerade übersichtlicher, kompakter oder JavaScript-ähnlich. Abhilfe würde hier die Verwendung von Interfaces mit ihrer automatischen Referenzzählung bieten:
Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var
  Point: IPoint;
begin
  with Script do
  begin
    Point:=New(Google.Maps.Point(10,20));
    FMyMarker:=New(Google.Maps.Marker);
    FMyMarker.Position:=Point;
    FMyMarker.Map:=Maps[0];
  end;
end;
Listing 5
oder so kurz wie in Listing 3 ohne lokale Variable. TPoint würde in diesem Fall nach der Zuweisung zu TMyMarker.Position sofort automatisch freigegeben oder bei Listing 5 nach Verlassen der Methode. So weit - so gut.
Das Marker-Objekt würde so aber - wenn es nicht in FMyMarker (vom Typ IMarker) referenziert würde - sofort nach Beendigung der Methode Button1Click wieder freigegeben und so von der Karte verschwinden. Um da zu vermeiden, muß die Liste TScript.Markers Interfaces verwenden. Dadurch ergibt sich aber eine äußerst ungünstige Situation: Eine Zuweisung von nil zu FMyMarker bewirkt augenscheinlich gar nichts und erst das zusätzliche Löschen mit TScript.Markers.Delete(...) oder TScript.Markers.Remove(...) gibt den Marker tatsächlich frei:
Delphi-Quellcode:
procedure TForm1.Button2Click(Sender: TObject);
begin
  with Script do
  begin
    Markers.Remove(FMyMarker);
    FMyMarker:=nil;
  end;
end;
Listing 6
Die Notwendigkeit der mehrfachen Freigabe macht die Programmierung nicht gerade übersichtlicher und bedeutet gegenüber der Nutzung reiner Objekte einen Rückschritt.
Wäre es nicht bedeutend einfacher - zusätzlich zu den Möglichkeiten, die die Referenzzählung über ein Interface bietet -, ein Objekt explizit freigeben zu können - unabhängig davon, wieviele Referenzen noch bestehen -, als dessen Folge das Objekt aktiv alle Verweise auf nil setzt und sich in allen Listen abmeldet?
Delphi-Quellcode:
procedure TForm1.Button2Click(Sender: TObject);
begin
  FMyMarker.Free;
end;
Listing 7
Daraufhin wäre FMyMarker nil und der Marker ist nicht mehr in der Liste TScript.Markers enthalten.
Anders herum entfernt
Delphi-Quellcode:
procedure TForm1.Button2Click(Sender: TObject);
begin
  Script.Markers[...].Free;
  //oder
  Script.Markets.Delete(...);
  //oder
  Script.Markers.Remove(...);
end;
Listing 8
den Marker aus der Liste und setzt FMyMarker auf nil.
Das wäre ein erheblicher Fortschritt, würde die Vorteile der Verwendung von reinen Objekten mit denen von Interfaces verbinden und die Möglichkeiten sogar noch erweitern.

Über derartige intelligente Zeiger und Objekte wurde schon einiges geschrieben - allerdings setzen alle mir bekannten Lösungen für Delphi auf die Verwendung von Generics und/oder anonymen Methoden und schließen damit ältere Compiler aus. Das Delphi Framework für Google Maps soll aber auch weiterhin ab Delphi 5 verwendbar sein.

Deshalb wurde folgendes Interface entworfen:
Delphi-Quellcode:
type
  INotify = interface(IInterface)
    ['{D37C5177-D900-4D99-A97B-A341865B258D}']
    procedure AddRef(const Ref);
    procedure AddNotify(const Notify: INotify);
    procedure Free;
    procedure FreeNotify(const Notify: INotify);
    procedure RemoveRef(const Ref);
    procedure RemoveNotify(const Notify: INotify);
    function _ReleaseSave: Integer;
    function GetObject: TObject;
    function GetRefCount: Integer;
    function IsDestroying: Boolean;
    property RefCount: Integer read GetRefCount;
  end;
Listing 9
Es unterstützt drei Verfahren zur Referenzverwaltung:
  1. Die automatische Referenz auf Variablen im Speicher (lokal und global) unter Verwendung von Interfaces.
  2. Die manuelle Referenz auf Variablen im Speicher (lokal und global) unter Verwendung der Methode AddRef().
  3. Die Benachrichtigung über die Freigabe unter Verwendung der Methode AddNotify().
Zusätzlich kann zur Kontrolle der Stand des Interface-Referenzzählers über RefCount beziehungsweise GetRefCount ausgelesen werden.
Wird das Objekt, das INotify implementiert, freigegeben, informiert es alle angemeldeten Schnittstellen über FreeNotify und setzt alle Speicherreferenzen auf nil.
Die Funktion GetObject unterstützt ältere Compiler, die noch keinen Interface-to-Object-Cast besitzen. IsDestroying liefert true, sobald sich das Objekt hinter dem Interface in der Methode Destroy befindet. Das ist notwendig bei Listen - genauer gesagt bei TObjectList -, um einen Mehrfachaufruf des Destructors zu vermeiden.
Zu erwähnen wäre noch _ReleaseSave: Damit wird das unangenehme Verhalten von TInterfacedObject vermieden, daß das Objekt nach Abfrage des Interfaces gleich wieder zerstört wird, wenn vorher der Referenzzähler nicht erhöht wurde:
Delphi-Quellcode:
procedure TForm1.Button3Click(Sender: TObject);
var
  o: TInterfaceObject;
begin
  o:=TInterfacedObject.Create;
  if Supports(o,IInterface) then ;
  o. ...; //<- geht schief, da das Objekt inzwischen freigegeben wurde
end;
Listing 10
Konkret sieht das so aus:
Delphi-Quellcode:
procedure TForm1.Button4Click(Sender: TObject);
var
  o1, o2: INotifyObject;
begin
  o1:=TNotifyObject.Create;
  o2:=o1;
  o1.Free;
  //sowohl o1 als auch o2 sind jetzt nil!!!
end;
Listing 11
Listen benutzen die Benachrichtigungsmethode, da direkte Speicherreferenzen fatale Fehler ergeben würden: Das Einfügen und Entfernen von Elementen führt zu einer Verschiebung der Zeiger und damit zu veränderlichen Speicheradressen. Bei Listen, die das INotify-Interface unterstützen, sieht das folgendermaßen aus:
Delphi-Quellcode:
procedure TForm1.Button5Click(Sender: TObject);
var
  o: TNotifyObject;
  l: TList;
begin
  o:=TNotifyObject.Create;
  o.AddRef(o); //<- bei Freigabe Variable auf nil setzen
  l:=TList.Create;
  try
    l.Add(o);
    o.Free; //Abmeldung bei der Liste und o auf nil setzen
    ShowMessage(IntToStr(l.Count));
    if not assigned(o)
      then ShowMessage('o=nil');
  finally
    l.Free
  end;
end;
Listing 12
Eine wichtiger Unterschied besteht allerdings bei den Aufrufen von TNotifyObject.Free und INotify.Free:
Die Methode Free des Objektes kann auch bei nil ausgeführt werden, da sie immer existiert und erst bei der Ausführung getestet wird, ob das Objekt vorhanden ist. Im Gegensatz dazu führt der Versuch, die Interface-Methode bei nil aufzurufen, zu einer Zugriffsverletzung.

Geplant ist, diese Technik in der kommenden Version der Frameworks einzusetzen. Im Gegensatz zu stahli's Lösung ist sie aber so allgemein gehalten, daß alle Objekte, die das INotify-Interface unterstützen oder einfach von TNotifyObject abgeleitet werden, an diesem Mechanismus teilhaben können. Die wichtigsten Listen TList, TObjectList, TThreadList und TInterfaceList wurden mit dieser Schnittstelle ausgerüsten und stehen so allgemein zur Verfügung.

Furtbichler 5. Mär 2012 07:01

AW: Intelligente Objekte - automatische Freigabe von Referenzen
 
Die Lösung funktioniert und ist elegant, keine Frage, aber Ich kann mir nicht helfen: Ich sehe darin einen Versuch, schlechtes Design nachträglich zu vertuschen.

Es ist doch so:
Wenn ich in einer Klasse einen Verweis auf ein externes Objekt habe, das jederzeit freigegeben werden könnte, dann breche ich mir doch einen ab, Code für diesen Verweis zu schreiben, weil ich jederzeit und immer befürchten muss, das mir der Zeiger unterm Arsch weggezogen wird. Sicheren Code kann ich ohne zusätzliche Verwendung von Critical Sections so nicht schreiben:

Delphi-Quellcode:
  If Assigned (FMyMarker) Then // <--- klappt noch
                               // hier wird der Marker freigegeben
    FMyMarker.Bar();          // <--- PENG
Mit weniger Code auskommen heißt nicht, es besser zu machen. 'Kompakter' Code ist nicht gleichbedeutend mit wartbar, lesbar oder robust. In meinen Augen ist es der Lesbarkeit nicht dienlich, solche Seiteneffekte zu implementieren. Ohne zusätzliche Aktionen ist o.g. Code zwar augenscheinlich sicher, aber der Fehler ist nur sehr schwer zu lokalisieren ("Wieso ist der Pointer auf einmal nil? Ich hab doch extra eine Abfrage eingebaut?")

In diesem Fall würde ich mit einem Handle arbeiten, und bei der Verwendung eines Markers explizit ein (Singleton-)Objekt anfordern, die Arbeiten ausführen und dann, wenn ich fertig bin, wieder zurückgeben, ähnlich einer TThreadList.

Das bedeutet, das der Code innerhalb der Anforderung/Rückgabe 100% sicher ist.
Delphi-Quellcode:
MyMarker := MyGoogleContainer.LockObject(FMyMarkerHandle);
If Assigned(MyMarker) Then
  Try
    MyMarker.Foo();
  Finally
    MyGoogleContainer.Unlock(MyMarker);
  End;
Wer nun meint, das das mit dem Try..Finally schlecht(er) lesbar ist, der refaktorisiert das eben in eine lokale Methode mit aussagekräftigem Namen.

Die entgültige Freigabe des Objektes obliegt dem Erzeuger, hier vermutlich dem Skript-Objekt oder dem Google-Maps Framework.
Der Verwender des Frameworks darf natürlich explizit die Marker entgültig freigeben, allerdings nicht direkt, sondern über eine Methode des Frameworks ('ReleaseMarker');

Eine anschließende Anforderung eines (mittlerweile ungültigen) Handles liefert ein NIL-Objekt zurück, auf das ich explizit und gewollt reagieren kann.

Aber vielleicht habe ich das entscheidende übersehen: Wie löst Du das Problem des 'unterm Arsch wegziehen'?

himitsu 5. Mär 2012 07:11

AW: Intelligente Objekte - automatische Freigabe von Referenzen
 
Ich würde das Ding, ganz einfach nur als Strohdoofes und ganz normales Interface auslegen.

Es wird freigegeben wenn alle Referenzen auf nil stehen
und es verändert nicht von innen her seine Referenzen.

Wenn der Punkt nicht mehr sichtbar sein soll, wird er nur aus den Googleobjekten/-listen rausgenommen und maximal in den Punkt-Objekt noch ein Flag gesetzt "ich bin gelöscht", welches man auswerten könnte, wenn doch noch jemand mal auf eine Methode des Objektes zugreifen will, obwohl es "eigentlich" nicht mehr existiert, bzw. nicht mehr angezeigt wird.




Problem: Man markiert eine Speicherposition 'ner lokalen Variable, die Prozedur wurde schon verlassen und Variable existiert nicht mehr.
Oder man markiert ein Feld in einem Objekt, gibt das Objekt frei und vergist die Markierung zu entfernen.
Wird jetzt das Objekt freigegeben und werden dann alle markierten Referenzen auf nil gesetzt, dann würden "falsche" Speicherbereiche überschrieben.

Ich wünsche dem armen Kerl/Mädl schonmal viel Spaß, welche(r) diesen Bug dann suchen darf, wo sich unvorhersehbar irgendwo etwas verändert, welches quasi einem Bufferoverrun ähnelt.

Stevie 5. Mär 2012 07:30

AW: Intelligente Objekte - automatische Freigabe von Referenzen
 
Sowas passiert halt, wenn man Code aus einer GC Sprache 1 zu 1 in Delphi übersetzt ;)

himitsu 5. Mär 2012 07:37

AW: Intelligente Objekte - automatische Freigabe von Referenzen
 
In Delphi haben wir ja auch sowas wie einen GC und das nennt sich Interface (String und dyn. Array gehört auch mit dazu).

Stevie 5. Mär 2012 07:47

AW: Intelligente Objekte - automatische Freigabe von Referenzen
 
Zitat:

Zitat von himitsu (Beitrag 1154532)
In Delphi haben wir ja auch sowas wie einen GC und das nennt sich Interface (String und dyn. Array gehört auch mit dazu).

Interfaces und andere managed data types sind referenzgezählt. Da ist noch ein himmelweiter Unterschied zu einem GC.

Patito 5. Mär 2012 09:26

AW: Intelligente Objekte - automatische Freigabe von Referenzen
 
Zitat:

Zitat von himitsu (Beitrag 1154532)
In Delphi haben wir ja auch sowas wie einen GC und das nennt sich Interface (String und dyn. Array gehört auch mit dazu).

Wobei ich hier anzumerken hätte, dass es sich beim Referen-Zähler von Interfaces hauptsächlich um einen Design-Fehler von Delphi handelt. (Die Designer hatten damals wohl zu viel COM im Kopf).
Für COM mag das zwar einen gewissen Sinn haben, aber Interfaces in einer objektorientierten Sprache immer per Ref-Count zu verwalten ist im allgemeinen grober Unfug.

Auf Design-Fehlern dann irgendwelche Framework-Spezialitäten aufzubauen halte ich für äußerst fragwürdig...

Iwo Asnet 5. Mär 2012 09:31

AW: Intelligente Objekte - automatische Freigabe von Referenzen
 
Blöde Frage: Woher weiß ein GC, wann ein Objekt nicht mehr benötigt wird?
Nur durch den Scope? Oder wird nicht auch hier eine Art Referenzzähler verwendet?

Außerdem verstehe ich nicht, was an Referenzzählern grober Unfug sein soll. Ich dachte immer, das die Strings genauso verwaltet werden.

In diesem Fall wäre das zumindest eine sichere Alternative.

himitsu 5. Mär 2012 09:54

AW: Intelligente Objekte - automatische Freigabe von Referenzen
 
Der GC merkt sich nicht nur die Anzahl der Referenzen, sondern auch die Addressen der Referenzen selber ... er weiß also wo alle Referenzen liegen.

In diesem Sinne ist eine "billige" Referenzzählung wesentlich einfacher.
> nur ein Integer, anstatt einer rießigen Liste

Und nein, bei Interfaces müssen die referenzen gezählt werden, sonst weiß man ja nicht wann es keine mehr gibt, um das Interface dann zreitugeben.

Aber ja, auch interfaces kann man ohne Referenzzählung nutzen.
Siehe TComponent. Denn dieses kann man auch über ein Interface ansprechen, allerdings ohne Zählung, da dort das Objekt nicht über die Interfacereferenzen freigegeben wird, sonder über Free, denn sonst würde das Objekt schon gelöscht, wenn die letzte Interfacereferenz weg ist, aber irgendwo könnten dann "ungültige" Objektreferenzen rumliegen.

neo4a 5. Mär 2012 10:01

AW: Intelligente Objekte - automatische Freigabe von Referenzen
 
Zitat:

Zitat von Patito (Beitrag 1154542)
Auf Design-Fehlern dann irgendwelche Framework-Spezialitäten aufzubauen halte ich für äußerst fragwürdig...

Und deshalb machst Du jetzt genau was? Drei Punkte!?

Das Konzept beim Einsatz von Interfaces ist schon etwas vielschichtiger, so dass der Aspekt des RefCounting nur einer von vielen ist.

Stevie 5. Mär 2012 10:53

AW: Intelligente Objekte - automatische Freigabe von Referenzen
 
Fakt bei Delphi Interfaces sind folgende Dinge (zumindest meinem Verständnis und meinen Erfahrungen nach):
  • wenn man mit Interfaces arbeitet sollte man tunlichst vermeiden auf die Objekte dahinter zuzugreifen und noch viel mehr, Objekt und Interface Referenzen zu vermischen
  • wenn man sich auf das Programmieren gegen Interfaces entscheidet braucht man entweder RefCounting oder eine andere Art des Memory Managements (z.B. die von TComponent oder eines DI Container)
  • man braucht einen rein hierarchischen Objectgraph. Doppelt verlinkte oder zirkuläre Referenzen sind komplett zu vermeiden, da sonst das RefCounting komplett das Freigeben verhindert
  • weicht man vom RefCounting ab, kann es zu "dangling pointers" kommen

Behält man das jederzeit im Hinterkopf, kann man eine Menge Freude an Interfaces haben - die Nichtbeachtung birgt eine große Anzahl an möglichen Problemen.

bernau 5. Mär 2012 12:06

AW: Intelligente Objekte - automatische Freigabe von Referenzen
 
Kommt in meinem Code nicht wirklich oft vor, daß ein Objekt zwei Variablen (V1,V2) zugeordnet ist und aus dem Grund eine (V1) auf NIL steht und die andere (V2) nicht.

Ich habe da aber keinen großen Aufwand getrieben. Eine TObjectlist angelegt und jedes erzeugte Objekt in die TObjectlist geschrieben. Beim freigeben aus der TObjectlist wieder herausgelöscht. Wenn ich wissen wollte, ob das Objekt noch vorhanden ist, dann einfach in der Objektliste nachgeschaut. Ganz sicher ist diese Lösung natürlich nicht, denn Wenn ein Objekt (V1) freigegeben wird und ein Objekt erzeugt wird, was zufällig die gleiche Speicheradresse wie V2 hat, dann zeigt V2 zwar auf ein gültiges Objekt, aber eben nicht auf das ursprüngliche. Ist bisher aber nie passiert ;-)

Patito 5. Mär 2012 12:23

AW: Intelligente Objekte - automatische Freigabe von Referenzen
 
Zitat:

Zitat von Stevie (Beitrag 1154556)
Fakt bei Delphi Interfaces sind folgende Dinge (zumindest meinem Verständnis und meinen Erfahrungen nach):
  • wenn man mit Interfaces arbeitet sollte man tunlichst vermeiden auf die Objekte dahinter zuzugreifen und noch viel mehr, Objekt und Interface Referenzen zu vermischen
  • wenn man sich auf das Programmieren gegen Interfaces entscheidet braucht man entweder RefCounting oder eine andere Art des Memory Managements (z.B. die von TComponent oder eines DI Container)
  • man braucht einen rein hierarchischen Objectgraph. Doppelt verlinkte oder zirkuläre Referenzen sind komplett zu vermeiden, da sonst das RefCounting komplett das Freigeben verhindert
  • weicht man vom RefCounting ab, kann es zu "dangling pointers" kommen

Behält man das jederzeit im Hinterkopf, kann man eine Menge Freude an Interfaces haben - die Nichtbeachtung birgt eine große Anzahl an möglichen Problemen.

Zu Punkt 1:
Sobald man aber ein wenig tiefer in die Objektorientierung eintaucht und es mit diversen Design-Patterns zu tun bekommt wird das so nicht mehr funktionieren. Dieses "nicht mischen" von Objekt und Interface-Referenzen ist eine blöde Idee die vermutlich Leute erfunden haben, die mit aller Gewalt die Design-Fehler von Delphi als "as designed" verteidigen wollten. (Kommt das von Joanna Carter mit ihrer unsinnigen Goldenen Regel?!?). Im allgemeinen kastriert man sich damit die Anwendungsfälle von Interfaces so gewaltig weg, dass es so richtig wehtut.
Warum sollte z.B. ein Objekt das ein Interface unterstützt, mit dem ein Logger alle paar Tage mal ein paar Daten auslesen kann sich plötzlich automatisch zerstören nur weil gerade mal kein Logger an den Daten interessiert ist (RefCount Logger-Interface = 0)?!

Punkt 2:
Es ist auf jeden Fall richtig, dass man nicht verschiedene Arten des Memory-Managements für dasselbe Objekt mischen sollte. Ref-Counting ist für reine Daten-Typen ganz gut und für Objekte nur bei ganz simplen Objekt-Graphen sinnvoll.

Punkt 3:
Wenn man sich auf Ref-Counting einläßt muß man halt darunter leiden... Wenn man das Ref-Counting wie in TComponent so gut es geht abschaltet, kann man sich auch auf etwas kompliziertere Objekt-Graphen einlassen. Man muß dabei nur beachten, dass man bevor man ein Objekt freigibt alle Interface-Referenzen auf das Objekt eliminieren muß.

Insgesamt habe ich schon viel zu oft so Sätze vom "Objekt und Interfaces nicht mischen" und dem "immer im Hinterkopf behalten von irgendwelchen unsinnigen Regeln" gelesen, dass ich's langsam zum kotzen finde...

neo4a 5. Mär 2012 13:20

AW: Intelligente Objekte - automatische Freigabe von Referenzen
 
Zitat:

Zitat von Patito (Beitrag 1154578)
.

Fullquote und eine Liste simpler, bekannter Regeln mit ein paar deftigen, aber inhaltsarmen Sprüchen "umrahmen" ... ich glaube, Du schaffst es nicht auf die Liste meiner Lieblingsprosa. Zumal (zumindest mir) nicht klar wird, worauf Du mit Deiner Tirade überhaupt hinaus willst.

BTW, wenn Du Deinem Logger-Interface eine Referenz in z.B. einem Singleton-Object verschaffst, wird es sich auch in Wochen nicht selbst zerstören. Wäre halt deftiges Design, statt deftiger Sprüche.

implementation 5. Mär 2012 15:42

AW: Intelligente Objekte - automatische Freigabe von Referenzen
 
Ihr redet vollkommen aneinander vorbei. Patito bemängelt, dass Interfaces in Delphi anders umgesetzt sind, als sie in anderen Sprachen konzipiert sind - nämlich viel zu COM-orientiert.
Stevie verteidigt hingegen den praktischen Nutzen dieser "Falschumsetzung".

Zitat:

Zitat von neo4a (Beitrag 1154585)
BTW, wenn Du Deinem Logger-Interface eine Referenz in z.B. einem Singleton-Object verschaffst, wird es sich auch in Wochen nicht selbst zerstören. Wäre halt deftiges Design, statt deftiger Sprüche.

Singleton = globale Variable = nicht schön.
Interfaces wären hier tatsächlich um einiges angebrachter, hätte man da nicht die völlig unangebrachte Referenzzählung ins Spiel gebracht.

In Delphi heißt "Interface" immer "COM-Objekt". Wenn man dann Interfaces mal so benutzen will, wie in andern Sprachen problemlos möglich, knallts, weil sich die Speichermodelle vermischen.
Natürlich kann man sich das ganze jetzt zu Nutzen machen und Frameworks darauf basieren lassen.

neo4a 5. Mär 2012 15:54

AW: Intelligente Objekte - automatische Freigabe von Referenzen
 
Zitat:

Zitat von implementation (Beitrag 1154611)
Zitat:

Zitat von neo4a (Beitrag 1154585)
BTW, wenn Du Deinem Logger-Interface eine Referenz in z.B. einem Singleton-Object verschaffst, wird es sich auch in Wochen nicht selbst zerstören. Wäre halt deftiges Design, statt deftiger Sprüche.

Singleton = globale Variable = nicht schön.

Singleton = DI-Container-Referenz = schon besser ;)

stahli 5. Mär 2012 16:20

AW: Intelligente Objekte - automatische Freigabe von Referenzen
 
Da ich ja auch direkt angesprochen war, will ich auch mal...

Ich habe bisher mit persistenten Objekten gearbeitet, die die gesamten Daten sowie die BL enthielten und beliebig komplex aufeinander verweisen konnten.
So konnte ein Personenobjekt ("A.Stahl") von mehreren Vereinsmitglied-, Spieler- und Schiedsrichterobjekten referenziert werden.

Öffnet der User ein neues Turnier, werden alle Objekte aufgelöst und neue erzeugt. Über die Owner-Beziehungen wird die Datenstruktur definiert.

Nun könnte eine referenzierte Person ("A.Stahl") u.U. irgendwann aufgelöst werden (abgesehen davon, dass das die BL natürlich ggf. auch verhindert).
In einem solchen Fall wollte ich gern, dass die betreffenden Personenreferenzen automatisch genilt werden.

Meine Überlegung war auch, dass Neulinge der OOP intuitiv davon ausgehen, dass solche Referenzen NIL werden. Das Objekt ist ja halt "weg".

Natürlich ist es möglich (das war mir auch damals klar), die Referenzen extra zu verwalten und Referenzen explizit zu nilen. Ich hätte mir jedoch eine Compilerlösung gewünscht, die das automatisch regelt.

Soviel zum einfachen Anliegen.


Inzwischen habe ich mich mit ein wenig mit Interfaces beschäftigt und will künftig auch mit diesen arbeiten.

Dann will ich an zentraler Stelle Interfaces abrufen können (z.B. IPerson(123)), die die Objekte erzeugt und verwaltet und die abgefragten Schnittstellen heraus gibt. Wird ein Objekt länger nicht benötigt, kann es aus einer Liste innerhalb der zentrale freigegeben und damit aufgelöst werden.


Ich will also künftig i.d.R. keine festen Verbindungen zwischen den Objekten mehr haben. Statt einer festen Referenz "Player.Person" würde künftig eine Personeninterface anhand der PersonenID abgefordert werden.
(So lässt sich auch eine DB vernünftig nutzen und es müssen nicht alle Daten komplett im Hauptspeicher liegen.)


Insofern hat sich das Problem für mich eigentlich erledigt (sofern ich das später alles so umsetzen kann, wie eben beschrieben).


Bei der klassischen RefCount-Nutzung der Interfaces stört mich eigentlich, dass man noch auf das dahinter liegende Objekt zugreifen kann, obwohl es eigentlich schon aufgelöst sein sollte (weil irgendwo noch eine Referenz "hängen geblieben ist"). Ich könnte also ggf. fleißig weiter auf eine Person zugreifen deren RefCount noch nicht bei 0 liegt, obwohl bereits ein neues Turnier geöffnet wurde). Der Zugriff auf ein aufgelöstest und geniltes Objekt würde wenigstens einen sichtbaren Fehler erzeugen.


Fazit: Man sollte Objekte bzw. Interfaces möglichst an einer zentralen Stelle anfordern und verwalten und auf feste (dauerhafte) Referenzen möglichst verzichten. Das scheint mir (nach meiner aktuellen Einschätzung) am sinnvollsten zu sein.


(Aber ich lerne als Hobbyprogrammierer halt immer nur stückweise aus meinen eigenen Fehlern. Vielleicht sehe ich das bald schon wieder anders ;-))


EDIT @implementation:Was ist denn der wesentliche Unterschied von Delphi-Interfaces zu Interfaces anderer Sparachen?

implementation 5. Mär 2012 16:40

AW: Intelligente Objekte - automatische Freigabe von Referenzen
 
Zitat:

Zitat von stahli (Beitrag 1154625)
EDIT @implementation:Was ist denn der wesentliche Unterschied von Delphi-Interfaces zu Interfaces anderer Sparachen?

Interfaces an sich bedeuten erst einmal nur, dass ein gemeinsamer Nenner definiert wird, den alle implementierenden Objekte haben sollen.
Angenommen du hast ein Handtuch und ein Auto. Was haben die gemeinsam? Man kann sie trocknen. Also implementieren sie beide ITrockenbar.
Nun kann es also irgendwo eine Prozedur Trocknen geben, die ein solches ITrockenbar als Parameter will.

In Delphi muss man sich dann auch als Aufrufer höllische Gedanken über die Speicherverwaltung machen. Sowas ginge dann schief:
Delphi-Quellcode:
var a: TAuto; h: THandtuch;
begin
  ...
  try
    ...
    Trocknen(a); // Huppsala
    ...
  finally
    ...
  end;
end;
Stattdessen muss man sich dann damit behelfen, komplett nur Interfaces zu nutzen.
Da Objekte und Interfaces aber zur Interaktion konzipiert sind, ist es vollkommener Humbug, beiden verschiedene Speichermodelle zu geben. *
Entweder beide manuell freigegeben, oder beide referenzgezählt (->Vala), oder auch für alles GC (->Java,.Net)



* der FPC kennt mittlerweile
Delphi-Quellcode:
{$interfaces corba}
, wo die Interfaces auf Referenzzählung und sonstige COM-Last verzichten. Könnte Emba auch mal einführen.

Robotiker 5. Mär 2012 17:09

AW: Intelligente Objekte - automatische Freigabe von Referenzen
 
Hallo,

wenn ich diesen Thread so lese, denke ich der Umgang mit VCL-Objekten ist im C++ Builder in diesem Sinne einfacher geregelt. Da ist z.B. sowas üblich

Code:
void __fastcall TfrmMain::btnTestClick(TObject *Sender)
{
    scoped_ptr<TStringList> list(new TStringList);
 
    list->Add(L"Eins");
    list->Add(L"Zwei");
    list->Add(L"Drei");
}
Wenn die Funktion verlassen wird, auch über eine Exception, löscht der Smartpointer die Stringlist.

Zitat:

Zitat von stahli (Beitrag 1154625)
Meine Überlegung war auch, dass Neulinge der OOP intuitiv davon ausgehen, dass solche Referenzen NIL werden. Das Objekt ist ja halt "weg".

Natürlich ist es möglich (das war mir auch damals klar), die Referenzen extra zu verwalten und Referenzen explizit zu nilen. Ich hätte mir jedoch eine Compilerlösung gewünscht, die das automatisch regelt.

Das wäre dann ein Fall für shared_ptr und weak_ptr, erstere sind referenzzählend, letztere werden ungültig, wenn kein shared_ptr mehr auf "ihr" Objekt zeigt.

Das Anlegen sähe, wenn der Compiler schon C++11 könnte, dann so aus:
Code:
  auto liste = make_shared(new TStringList);
(Das auto ermittelt den Typ der Variable entsprechend dem Ausdruck auf der rechten Seite der Zuweisung.)

himitsu 5. Mär 2012 17:26

AW: Intelligente Objekte - automatische Freigabe von Referenzen
 
Und wie verwaltet corba dann die Referenzen?

Robotiker 5. Mär 2012 18:10

AW: Intelligente Objekte - automatische Freigabe von Referenzen
 
Zitat:

Zitat von himitsu (Beitrag 1154655)
Und wie verwaltet corba dann die Referenzen?

Aus "Common Object Request Broker Architecture" würde ich mal schließen, da gibt einen Broker, der das tut. Ganz ähnlich wie der Vorschlag von Stahli.

Ein Interface entspräche in etwa nur dem, was man in C++ darunter versteht. Da ist ein Interface nur eine Basisklasse, die nur abstrakte Funktionen enthält. Da es in C++ Mehrfachvererbung gibt, kann eine Klasse so auch beliebig viele Interfaces implementieren. Technisch ist so ein Interface nur eine Tabelle von Funktionszeigern.

Furtbichler 5. Mär 2012 19:00

AW: Intelligente Objekte - automatische Freigabe von Referenzen
 
Ich frage hier nochmals nach:

Wenn man also Objektreferenzen verwendet, die automatisch genullt werden, wenn das referenzierte Objekt freigegeben wird, wie sieht dann so ein Programm aus? Wie sichert man sich gegen spontan auftretende Nil-Referenzen ab? Kann jemand hier mal ein Beispiel nennen?

stahli 5. Mär 2012 19:36

AW: Intelligente Objekte - automatische Freigabe von Referenzen
 
@Furtbichler:

Ich habe doch oben ein Besipiel beschrieben (wenngleich ich inzwischen ja auch einen anderen Ansatz wählen würde):

Eine Person wird von mehreren Spielerobjekten referenziert (damit alle die selben Daten verwenden bzw. anzeigen).
Wird die Person freigegeben, sollen alle Spielerobjekte erkennen, dass das Personenobjekt nicht mehr existiert (indem sie das Feld auf nil prüfen).
Natürlich sollte vermieden werden, dass das referenzierte Objekt nach dem Prüfen auf nil aufgelöst wird. Aber das ist ja sowiso klar.

Natürlich kann man das anders (besser) regeln, aber WENN man rein mit direkt referenzierten Objekten arbeitet, sollte der Wunsch doch nachvollziehbar sein.

DataSource informiert ja auch DBGrids, über seine Auflösung (über Observer-Pattern). Im Sinne einer einfachen Programmierung und aus Rücksicht auf OOP-Anfänger wäre es nur ganz schön, wenn es dafür einen Automatismus gäbe.

Ich sehe ein, dass das vielleicht nicht ganz einfach zu realisieren ist, aber Deine Nachfrage verstehe ich nicht.

MyDBGrid.DataSource wird ja auch nicht spontan auf nil gesetzt, sondern nur wenn die gebundene DataSource aufgelöst wird.


@Robotiker:
Corba sieht wirklich interessant aus.
http://de.wikipedia.org/wiki/Common_...r_Architecture
http://www.borland.com/de/products/v...ker/index.html
Aber es ist halt wie immer. Ich verstehe das nur zum (Bruch-)Teil. :-(

BUG 5. Mär 2012 20:06

AW: Intelligente Objekte - automatische Freigabe von Referenzen
 
Zitat:

Zitat von Furtbichler (Beitrag 1154666)
Wie sichert man sich gegen spontan auftretende Nil-Referenzen ab? Kann jemand hier mal ein Beispiel nennen?

Threads machen sowas natürlich nicht einfacher :mrgreen:
Aber Absichern vor spontanen Verschwinden bei Zugriff durch mehrere Threads schreit nach Synchronisation, sollte eigentlich mit einer beliebigen Lösung des Reader-Writer-Problems behandelt werden können.

Furtbichler 5. Mär 2012 21:23

AW: Intelligente Objekte - automatische Freigabe von Referenzen
 
Zitat:

Zitat von stahli (Beitrag 1154670)
Ich habe doch oben ein Besipiel beschrieben ...

Das, was Du beschreibst, ist nicht sicher.

Zitat:

Corba sieht wirklich interessant aus.
Ich dachte, Corba wäre out.

Zitat:

Zitat von BUG (Beitrag 1154672)
Aber Absichern vor spontanen Verschwinden bei Zugriff durch mehrere Threads schreit nach Synchronisation

Eben. Aber was läuft im Thread? Irgendwas vom Framework, was mir spontan die Pointer klaut? Das ist Overkill und imho wirklich unsauber.

Ich kann die Motivation von Stahli verstehen, auch der Lösungsansatz bzw. die Idee dahinter von Thom verstehe ich.. Aber notwendig und dann wirklich sauber ist das eben nicht.

Ich würde nie im Leben mit einem System arbeiten, das mir die Immanzenz meiner Objekte nicht sicherstellt. Und genau das wird hier gemacht. Ich muss immer und jederzeit damit rechnen, das mir eine Objektreferenz geklaut wird. Grauselig.

Aber ich schreibe auch keine heterarchischen Systeme wie Stahli. Vermutlich werde ich ähnliche Gehirnakrobatiken anstellen müssen und dann dankbar diesen Thread lesen, wenn ich das mal mache.

Oder ich schreibe keine Heterarchien, stattdessen aber ein Spielermanagement, das mir meine Spieler verwaltet.

stahli 5. Mär 2012 22:30

AW: Intelligente Objekte - automatische Freigabe von Referenzen
 
Zitat:

Zitat von Furtbichler (Beitrag 1154674)
Das, was Du beschreibst, ist nicht sicher.

Versetze Dich halt mal in eine frühere Entwicklungsstufe zurück. ;-)
Da ich nicht mit Threads gearbeitet habe und alle Datenobjekte im Speicher verwaltet werden können, funktioniert das letztlich doch zuverlässig.
Inzwischen erkenne ich auch, dass es bessere und vor allem flexiblere Verfahrensweisen gibt. Allerdings bringen die natürlich auch einigen Aufwand und Abstraktion mit sich, so dass man sich "im ersten Moment" eher für einen naheliegenderen Ansatz entscheiden wird. Jedenfalls, wenn man mit diesem noch nicht an bestimmte Grenzen gekommen ist und keine Ausbildung als Programmierer genossen hat.


Zitat:

Zitat von Furtbichler (Beitrag 1154674)
Ich dachte, Corba wäre out.

Habe ich auch gelesen. Die Beschreibung des Konzeptes klingt aber sehr nützlich.
Es wäre wohl gut, wenn sich endlich mal ein entsprechendes Konzept durchsetzen würde, mit dem auch Nicht-Profis mit Delphi arbeiten können.
Was soll denn jetzt "in" sein? DataSnap?


Zitat:

Zitat von Furtbichler (Beitrag 1154674)
Ich kann die Motivation von Stahli verstehen, auch der Lösungsansatz bzw. die Idee dahinter von Thom verstehe ich.. Aber notwendig und dann wirklich sauber ist das eben nicht.
Ich würde nie im Leben mit einem System arbeiten, das mir die Immanzenz meiner Objekte nicht sicherstellt. Und genau das wird hier gemacht. Ich muss immer und jederzeit damit rechnen, das mir eine Objektreferenz geklaut wird. Grauselig.
Aber ich schreibe auch keine heterarchischen Systeme wie Stahli. Vermutlich werde ich ähnliche Gehirnakrobatiken anstellen müssen und dann dankbar diesen Thread lesen, wenn ich das mal mache.
Oder ich schreibe keine Heterarchien, stattdessen aber ein Spielermanagement, das mir meine Spieler verwaltet.

Ich kann ja kaum den Namen richtig aussprechen, programmiere aber Heterachische Systeme - Wahnsinn.
Wie gesagt, ich habe mit meinen Fähigkeiten (ohne Threads) mein Projekt immer weiter ausgebaut und diverse Wege bestritten. Mit den Objekten konnte ich am flexibelsten arbeiten. Die Klassen habe ich mir teilweise durch einen Experten automatisch erzeugen lassen. In einem Framework binde ich die Objekte automatisiert an die GUI. Dabei ist es hilfreich, wenn die Objekte dauerhaft im Speicher vorliegen.
Das funktioniert eigentlich wunderbar und mit rel. geringem Aufwand (als das Framework funktionierte).

Da ich verschiedene Turniersysteme parallel verwalte und die Spieler/Personen in allen Turniersystemen eingesetzt werden können, wird es inzwischen aber dennoch sehr unübersichtlich. Außerdem möchte ich künftig eine Datenbank oder sogar Client/Server einsetzen. Dann funktioniert es natürlich nicht mehr auf dem bisherigen Weg.

Deshalb plane ich eine Änderung des gesamten Konzeptes, muss damit aber natürlich auch erst meine Erfahrungen machen.

Man geht halt erst einmal den einfachen Weg, bis man erkennt, dass es so nicht weiter geht...

Robotiker 6. Mär 2012 07:46

AW: Intelligente Objekte - automatische Freigabe von Referenzen
 
Zitat:

Zitat von Furtbichler (Beitrag 1154666)
Ich frage hier nochmals nach:

Wenn man also Objektreferenzen verwendet, die automatisch genullt werden, wenn das referenzierte Objekt freigegeben wird, wie sieht dann so ein Programm aus? Wie sichert man sich gegen spontan auftretende Nil-Referenzen ab? Kann jemand hier mal ein Beispiel nennen?

Wie das aussehen kann, kannst du in der Doku der vom C++ Builder verwendeten Bibliothek nachlesen:
http://www.boost.org/doc/libs/1_49_0.../smart_ptr.htm

Ein weak_ptr hat z.B. eine Memberfunktion expired() mit der man prüfen kann, ob er noch gültig ist.

Greift man auf einen ungültigen Pointer zu gilt
Zitat:

When the last shared_ptr to the object goes away and the object is deleted, the attempt to obtain a shared_ptr from the weak_ptr instances that refer to the deleted object will fail: the constructor will throw an exception of type boost::bad_weak_ptr, and weak_ptr::lock will return an empty shared_ptr.

Zitat:

Zitat von Furtbichler (Beitrag 1154674)
Zitat:

Corba sieht wirklich interessant aus.
Ich dachte, Corba wäre out.

Es ist gewissermaßen unter seinem Eigengewicht zusammengebrochen.

Zitat:

Zitat von BUG (Beitrag 1154672)
Aber Absichern vor spontanen Verschwinden bei Zugriff durch mehrere Threads schreit nach Synchronisation, sollte eigentlich mit einer beliebigen Lösung des Reader-Writer-Problems behandelt werden können.

Ja, siehe
http://www.boost.org/doc/libs/1_49_0...m#ThreadSafety

Zitat:

Zitat von stahli (Beitrag 1154677)
Versetze Dich halt mal in eine frühere Entwicklungsstufe zurück. ;-)

Die Themen Corba und Smartpointer waren zu Zeiten des C++ Builder 3/4/5 sehr modern.

Corba ist in der Versenkung verschwunden, die Smartpointer sind heute ISO-Standard.

Thom 6. Mär 2012 10:49

AW: Intelligente Objekte - automatische Freigabe von Referenzen
 
Vielen Dank für alle Beiträge! Ich muß zugeben: Jeder hat in etwa das geschrieben, was ich von ihm erwartet habe. :-D

Zuerst muß ich Stevie Recht geben: Diese Probleme entstehen, wenn man eine untypisierte GC Sprache nach Delphi umsetzen möchte... Aber bei diesem Ansatz will ich bleiben und deshalb soll und muß aller Verwaltungsaufwand für den Anwender (des Frameworks) hinter den Kulissen bleiben. Der Programmierer soll sich voll und ganz auf die Umsetzung seiner Ideen konzentrieren können. Deshalb sollen auch keine zusätzlichen Aufrufe notwendig sein.


@Furtbichler:

Vielen Dank für Deine Antwort!
Deine Sorge besteht darin, daß irgendwelche fremden Programmteile Deinem eigenen Code "dazwischen pfuschen". Dieses Gefühl ist bei Multithreadanwendungen vollkommen berechtigt. Leider zeugt das aber auch davon, daß Du Dich - höchstwahrscheinlich - kein einziges mal mit dem von mir angesprochenen Framework beschäftigt hat. Das soll kein Vorwurf sein - schließlich ist das auch keine Pflicht. Hättest Du das aber gemacht, wüßtest Du, das es gar nicht threadsave sein muß, da die JScript-Engine von Microsoft nicht multithreadsicher ist.
Spontan auftretende nil-Zeiger der Art
Delphi-Quellcode:
if assigned(FMyMarker) then
begin
  //<- ist hier plötzlich weg
  FMyMarker. ...;
end;
können also gar nicht auftreten. Auch alle asynchronen JScript-Callbacks laufen im Context des Hauptthreads.

Wie threadsicher ein Interface ist, hängt von seiner Implementation ab, nicht von seiner Definition. Wie das INotify.Free umgesetzt wird - ob als direkte, unmittelbare Freigabe in Singlethread-Anwendungen oder "angemeldet" und zeitlich verzögert-, hängt ganz von den Erfordernissen ab.
Ich gebe Dir aber vollkommen Recht: In Multithreadanwendungen muß ein höherer Verwaltungsaufwand betrieben werden, als in einem Programm, in dem nur ein Thread (in der Regel der Hauptthread) auf den Datenbestand zugreift. Das vorgestelle Interface wurde von mir primär für das Framework entworfen, um die automatisch Speicherverwaltung von Delphi über Referenzzähler nutzen zu können ohne die Nachteile eines TInterfacedObject's. Für eine darüber hinausgehende Anwendung sind ganz bestimmt noch weitere Aspekte zu berücksichtigen.


@himitsu:

Das vorgestellte Interface ist von IInterface abgeleitet. Deshalb beinhaltet das implementierende Objekt INotifyObjekt auch eine Referenzzählung mit _AddRef und _Release. Mir geht es aber darum, ein referenzgezähltes Objekt explizit freigeben zu können, ohne daß es zu Zugriffsverletzungen über andere, parallel existierende Referenzen kommt.
Die Registrierung/Deregistrierung lokaler (Interface-)Variablen auf dem Stack erfolgt automatisch. Das bedeutet, daß nach Verlassen der Methode die Referenz wieder entfernt wird. Es kann also nicht vorkommen,
Delphi-Quellcode:
type
  TForm1 = class([...])
    [...]
  private
    FMyNotify: INotify;
  end;

procedure TForm1.Button1Click(Sender: TObject);
var
  o: INotify;
begin
  o:=TNotifyObject.Create;
  FMyNotify:=o;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  FMyNotify:=nil;
end;
daß jetzt, bei Freigabe des Objektes in Button2Click, die (Stack-)Variable "o" auf nil gesetzt wird. "o" wird bei der Zuweisung in Button1Click registriert und nach Beendigung der Methode vom Compiler auf nil gesetzt sowie über INotify.RemoveRef(o) abgemeldet. Alles ganz einfach und vollautomatisch. Ich will das mal "managed Reference" nennen.
Anders sieht es natürlich bei einer expliziten Registrierung einer Variablen über AddRef() aus - also einer "unmanaged Reference". Hier muß natürlich dafür gesorgt werden, daß es nicht zu Zugriffsverletzungen kommt. Ich würde es einmal vergleichen mit dem Aufruf eines xxx.Lock: Wird anschließend das xxx.Unlock vergessen, gibt es logischerweise Probleme. Das hat aber nichts mit Fehlern im Konzept, sondern mit der Vergeßlichkeit des Programmieres zu tun. Das von mir vorgestelle Interface kann die Arbeit wesentlich erleichtern - ist aber keine Lizenz zum Abschalten des eigenen Gehirns.

Meine Umsetztung funktioniert in den bisherigen Tests sehr zuverlässig.


@Patito:

Hast Du auch irgend etwas Sachliches zu dem Thema beitragen oder beschränkst Du Dich immer auf platte Statements?

Patito 7. Mär 2012 12:32

AW: Intelligente Objekte - automatische Freigabe von Referenzen
 
Zitat:

Zitat von Thom (Beitrag 1154731)

Meine Umsetztung funktioniert in den bisherigen Tests sehr zuverlässig.

@Patito:

Hast Du auch irgend etwas Sachliches zu dem Thema beitragen oder beschränkst Du Dich immer auf platte Statements?

Meine Aussagen sind folgende:
1. Dass es zumindest fragwürdig ist Dinge auf Design-Fehlern aufzubauen.
2. Dass Interfaces nicht für das Ref-Counting da sind. (Interfaces sind Schnittstellen)

Mag sein, dass Dir das nicht gefällt. Insgesamt hat es mit Deiner Situation aber nur insofern zu
tun, dass ich Deinen Tricks erst mal wenig vertraue.

Ich glaube nicht, dass Du das ganze richtig anpackst. Per Observer ein paar Referenzen zu eleminieren ist zwar
gute Technik, aber in einer Anwendung verteilte Referenzen im User-Code lassen sich nicht so einfach alle auf nil setzen.
Ich vermute mal, dass Du da in Deinen Tests einem Trick des Optimizers aufgesessen bist...

Delphi-Quellcode:
procedure TForm1.Button4Click(Sender: TObject);
var
  o1, o2: INotifyObject;
begin
  o1:=TNotifyObject.Create;
  o2:=o1;
  o1.Free;
  //sowohl o1 als auch o2 sind jetzt nil!!!
end;
Wäre interessant wenn Du die Referenzen etwas weiter weg verteilst.
(Feld in irgendeiner Klasse, auf dem Stack als Rückgabewert einer Funktion, ...).
Ich glaube, dass Du niemals alle auf nil gesetzt bekommen wirst.

So ein zwischen-Interface bringt reichlich wenig. Anstatt auf Interface-Referenzen aufpassen zu müssen
muss man jetzt eben genauso auf die Referenzen auf die INotifyObject-Interfaces aufpassen - damit hat man
praktisch nichts gewonnen.

Das ganze geht mit Objekt-Handles wesentlich einfacher und ohne 360-Grad Pirouette.


Alle Zeitangaben in WEZ +1. Es ist jetzt 04:06 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz