Thema: Delphi IsObject / IsClass

Einzelnen Beitrag anzeigen

choose

Registriert seit: 2. Nov 2003
Ort: Bei Kiel, SH
729 Beiträge
 
Delphi 2006 Architect
 
#1

IsObject / IsClass

  Alt 3. Feb 2004, 14:29
Oft wird Delphi-Neulingen geraten, bei der Arbeit mit Objekten die Referenzen nach der Freigabe eines Objekts (zB mit FreeAndNil) wieder auf nil zu setzen, damit ein Vergleich der Form
if Assigned(AnObject) then eingesetzt werden kann, um zu überprüfen, ob es sich um eine gültige Referenz handelt.
Der Compiler von Delphi initialisiert Objektreferenzen innerhalb von Methoden und Prozeduren/Funktionen nicht vor, so dass ein Test der Art
Delphi-Quellcode:
procedure MyProc;
var
  myObject: TObject;
begin
  if Assigned(myObject) then
zwar überprüft, ob die Referenz (hier: myObject) einen Wert hält, der von nil verschieden ist, kann aber im Fall einer "durch Zufall" von nil verschiedenen "Vorbelegung" nicht entscheiden, ob der Wert nun tatsächlich auf ein Objekt verweist.

Innerhalb des DEC und der JCL konnte ich nun zwei verschiedene Implementierungen einer Funktion IsObject (bei der JCL auch eine IsClass für Klassenreferenzen) finden, die zwei unterschiedliche Ansätze verfolgen.
Die Lösung von Hagen prüft, sofern ich sie nicht missdeute, ob vor dem Speicher, in dem das vermeintliche Objekt liegt, einen MagicCode enthält (genauer ein Bit), der vom Borland-Speichermanager dort hinterlegt worden sein sollte.
Die Lösung innerhalb der JCL geht davon aus, dass ein Objekt zu einer Klasse gehört und überprüft innerhalb der VMT der Klasse, ob die dort erwartete Referenz auf die Klasse selbst vorhanden ist.

Während Hagens Ansatz schneller arbeiten sollte kann bei zufälligen Werten (durch eine zufällig vorbelegte lokale Referenz) durch seine Maskierung der Form if MagicCode and $2 = $2 then nur zu 50% gesagt werden, ob es sich um ein Objekt handelt. Aus informationstheoretischer Sicht ist dies keine Information, also nutzlos für diesen Fall, obgleich die Routine für andere Szenarien korrekt arbeiten sollte. Darüber hinaus könnte dieser Ansatz nicht mehr funktionieren, wenn man die Speichervergabe von Objekten über eine eigene Implementierung (NodeManager) lösen würde, die ohne den MagicCode auskommt.
Der Ansatz der JCL prüft zwar ein wesentlich unwahrscheinlicheres Kriterium, hat aber gegenüber der Lösung aus dem DEC den Nachteil, das er mit diversen Indirektionen arbeitet, also im Speicher liest, obgleich es bei der Interpretation von nicht-initialisierten Referenzen sein kann, dass keine Leserechte zu den entsprechenden Speicherbereichen existieren. Hagens Lösung hingegen "schluckt" solche Fehler (durch einen try-except-Block) und gibt für diesen Fall den erwarteten Wert False zurück.

In der Vergangenheit habe ich eine zur JCL ähnliche Lösung entwickelt, die mithilfe der funktion IsBadReadPtr überprüft, ob die Bereiche gelesen werden können und außerdem beim Sonderfall nil abkürzt, so dass sie als Alternative für Assigned eingesetzt werden könnte.
Leider ist diese Implementierung etwas langsamer als der Ansatz der JCL und bei weitem inperformanter als die Lösung aus dem DEC.
Darüber hinaus vermag auch dieser Ansatz (genauso wie die beiden anderen) nicht das volgende Szenarium korrekt zu erfassen
Delphi-Quellcode:
var
  myObject: TObject;
begin
  myObject:= TObject.Create;
  myObject.Free;
  if IsObject(myObject) then
weil der Speicher hinter dem durch den Destructor freigegeben Objekt nicht gelöscht wird und somit weiterhin auf eine gültige Klasse verweist. Auch der MagicCode des Borland-Speichermanagers zeigt weiterhin das geforderte Kriterium, so dass ich bisher keine geeignete Lösung des Problems zur identifizierung einer gültigen Objektreferenz ausmachen konnte.

Hat jemand eine Lösung?
gruß, choose
  Mit Zitat antworten Zitat