AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

Referenzen auf ungültige Objekte

Ein Thema von stahli · begonnen am 14. Mär 2011 · letzter Beitrag vom 2. Mär 2012
Antwort Antwort
Seite 1 von 2  1 2      
Benutzerbild von stahli
stahli

Registriert seit: 26. Nov 2003
Ort: Halle/Saale
4.352 Beiträge
 
Delphi 11 Alexandria
 
#1

AW: Referenzen auf ungültige Objekte

  Alt 3. Nov 2011, 16:04
Also ist es so?

Ich habe 3 Interfaces I1, I2, I3 und erzeuge "in jedes" ein Objekt (O1, O2, O3).

Alle Interfaces haben den Referenzzähler 1.

MyProcedure(I2) erhöht für I2 den Referenzzähler auf 2 bis die Prozedur verlassen wird.

I4 := I2 erhöht wieder für I2 den Referenzzähler auf 2?
I2.Free löst das objekt dann noch nicht auf.
Über I4 wäre es noch ansprechbar?

Aber was wäre wenn man I1 := I3 zuweist? O1 würde aufgelöst und I3 der Referenzzähler erhöht?

Die Objekte selbst sollten dann aber auf keinen Fall händisch aufgelöst werden (also auch nicht aus einer TObjectList mit OwnObjects entfernt werden).

Wenn es einem nicht darum geht, eine Art Mehrfachvererbung zu nutzen (unterschiedliche Objekte mit gleichen Methoden), sondern nur die Referenzierungen sinnvoll behandeln will, dann ist das schon recht kompliziert und aufwendig.

Meine Überlegung war: Wenn für Interfaces die Referenzen vom Compiler überwacht und verwaltet werden, dann sollte das grundsätzlich ja auch für normale Objekte möglich sein. Ok, die müssten noch eine Referenzliste o.ä. erhalten, aber dann würde das automatisiert im Hintergrund ablaufen können.
Philips Lösung sieht ja schon richtig gut aus (ich werde das heute Abend mal ansehen, auch in Bezug auf Objektreferenzen in Propertys). Wenn der Compiler so etwas aber nativ verwurschteln würde wäre m.E. eine der größten Schwächen von Delphi abgestellt. Projekte ließen sich viel leichter realisieren, da ALLE Zugriffe auf aufgelöste Objekte auf NIL zugreifen würden (statt auf zufällige Speicherstellen).
Stahli
http://www.StahliSoft.de
---
"Jetzt muss ich seh´n, dass ich kein Denkfehler mach...!?" Dittsche (2004)
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.326 Beiträge
 
Delphi 12 Athens
 
#2

AW: Referenzen auf ungültige Objekte

  Alt 3. Nov 2011, 19:08
Man kann Interfaces auch ohne Referenzzählung laufen lassen.
Dann muß man entweder noch Zugriff auf die Objektreferenz haben oder man baut sich eine "gib dich frei"-Methode mit ein, worüber man das Interface dann freigeben kann.
Aber da ist zu beachten, daß bei freigabe alle übrigen Referenzen, sollten noch welche vorhanden sein, zum Absturz führen können, wenn diese feigegeben werden und Delphi dem Interface (welches ja nicht mehr existiert) dieses mitteilen will.

PS: Deswegen speichert man sich manchmal auch als Pointer gecastete Interfacereferenzen, da dort keine automatische Referenzzählung auftritt.


Aber: Nimm dir besser eine TInterfaceList, in dieser hälst du dir eine Referenz und so immer Eine übrig ist, wird das Interface frühestens dann freigegeben, wenn diese InterfaceListe ebenfalls seine Referenzen freigibt.
Ein Therapeut entspricht 1024 Gigapeut.
  Mit Zitat antworten Zitat
Benutzerbild von Sir Rufo
Sir Rufo

Registriert seit: 5. Jan 2005
Ort: Stadthagen
9.454 Beiträge
 
Delphi 10 Seattle Enterprise
 
#3

AW: Referenzen auf ungültige Objekte

  Alt 3. Nov 2011, 20:28
@stahli:

Wenn ich dich richtig verstehe, dann willst du für deine Objekte das gleiche Verhalten wie in einer Datenbank bei ForeignKeys.
Die können z.B. bei einer Löschung des Basis-Datensatzes alle verlinkten Datensätze entsprechend aktualisieren und dort die Referenz z.B. auf NULL setzen.

Ein Ansatz dazu wäre folgender:

Delphi-Quellcode:
type
  TTurnier = class
  private
    fPersonID : integer;
    procedure SetPerson( const Value : IPerson );
    function GetPerson : IPerson;
  public
    property Person : IPerson read GetPerson write SetPerson;
  end;

procedure SetPerson( const Value : IPerson );
begin
  fPersonID := Value.ID;
end;

function GetPerson : IPerson;
begin
  Result := GlobaleObjektListe.GetPerson( fPersonID );
end;
Jetzt kannst du bei Bedarf die Person aus der Turnier-Instanz holen und bekommst nur dann eine gülitge Instanz, wenn es diese Person auch noch in der GlobalenObjektListe enthalten ist.

Diese GlobaleObjektListe gibt die Instanzen allerdings nicht frei, sondern vergisst diese einfach nur (IPerson => Interface).
Dann sollte es nicht mehr rumsen und die Referenzen sind sauber.

Und dieses Rumgeeiere mit RTTI kannst du dir sparen
Kaum macht man's richtig - schon funktioniert's
Zertifikat: Sir Rufo (Fingerprint: ‎ea 0a 4c 14 0d b6 3a a4 c1 c5 b9 dc 90 9d f0 e9 de 13 da 60)
  Mit Zitat antworten Zitat
Furtbichler
(Gast)

n/a Beiträge
 
#4

AW: Referenzen auf ungültige Objekte

  Alt 3. Nov 2011, 22:19
Haltet ihr es nicht für ein 'design flaw', wenn ein Objekt von unbestimmt vielen anderen Objekten referenziert wird, während wieder irgend jemand meint, das Objekt auf den Müll werfen zu wollen?

Bei meiner Art zu programmieren (nicht das die besonders toll wäre), kommt so etwas einfach nicht vor. Ich kann mir das nur bei dem OOP-Pendant einer Lookupliste vorstellen. Hier würde ich aber eher die ID speichern (von mir aus der Index in die Liste). Aber selbst da hätte ich ein ungutes Gefühl, denn wenn irgendwer auf ein Objekt zugreift, das ihm von jemandem anderen unterm Ar*** weggezogen wird... also ich weiss nicht, irgendwie "unsauber".

Oder übersehe ich etwas?
  Mit Zitat antworten Zitat
Benutzerbild von Sir Rufo
Sir Rufo

Registriert seit: 5. Jan 2005
Ort: Stadthagen
9.454 Beiträge
 
Delphi 10 Seattle Enterprise
 
#5

AW: Referenzen auf ungültige Objekte

  Alt 3. Nov 2011, 22:45
Oder übersehe ich etwas?
Ja, stell dir einfach mal vor, du hast (wie hier schon von stahli skizziert) eben so ein Person-Objekt, welches sich an mehreren anderen Objekten befinden kann (die Person ist Spieler, Schiedsrichter, Sponsor, Depp für Alles )
An einer Stelle im Programm änderst du jetzt den Namen der Person von "Meier" auf "Müller".
Dann wäre es doch schön, wenn alle, die auf die gleiche Person referenzieren auch sofort "Müller" anzeigen und nicht noch den alten Stand mit "Meier".

Wenn du überall eine eigene Instanz benutzt, dann hast du eben das Problem alle Referenzen zu finden und zu aktualisieren.
Der Aufwand ist gleich, nur dass es eben nicht knallt.

Dafür gibt es aber halt die Interfaces ... da wird eben nicht freigeben, sondern es gibt sich selber frei.
Ein Problem bleibt aber, und das ist, wenn die Person tatsächlich aus dem gesamten Programmumfeld gelöscht werden soll, also die Person "Müller" gibt es nicht mehr.

Dann hilft der von mir beschriebene kombinierte Ansatz mit der ReferenzID und Interfaces
Kaum macht man's richtig - schon funktioniert's
Zertifikat: Sir Rufo (Fingerprint: ‎ea 0a 4c 14 0d b6 3a a4 c1 c5 b9 dc 90 9d f0 e9 de 13 da 60)
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.326 Beiträge
 
Delphi 12 Athens
 
#6

AW: Referenzen auf ungültige Objekte

  Alt 3. Nov 2011, 22:51
Solange immer nur Einer gleichzeitig für die Freigabe verantwortlich ist, ist es vollkommen egal, wieviele Referenzen auf ein Objekt zeigt.
Es sollte nur sichergestellt werden, daß keine fremden Referenzen mehr in Umlauf sind, sobald das Objekt freigegeben wird.


Zitat:
haltet ihr es nicht für ein 'design flaw', wenn ein Objekt von unbestimmt vielen Anderen Objekten referenziert wird,
Das ist eigentlich die Natur von Objektzeigern, denn sonst könnte man die nichtmal als Parameter weitergeben, wenn es nur eine Referenz geben dürfte.

Zitat:
während wieder irgend jemand meint, das Objekt auf den Müll werfen zu wollen?
Aber das sollte/muß man wirklich unterbinden. Und sei es auch dadurch, daß man den anderen irgendwie mitteilt, daß dieses Objekt nun verschwindet.
Ein Therapeut entspricht 1024 Gigapeut.
  Mit Zitat antworten Zitat
Benutzerbild von Bummi
Bummi

Registriert seit: 15. Jun 2010
Ort: Augsburg Bayern Süddeutschland
3.470 Beiträge
 
Delphi XE3 Enterprise
 
#7

AW: Referenzen auf ungültige Objekte

  Alt 3. Nov 2011, 23:25
ketzerischer Ansatz: wenn niemand den Zeiger auf das Objekt verwenden würde sondern einen Zeiger auf den Zeiger (um den sich der Destruktor des Objekts selbst kümmern muss) gäbe es immer einen gültigen Zugriff und ein nil würde sauber erkannt werden.
Teile von dem was Sir Rufo beschrieben hat würde ich als Observer sehen.
Thomas Wassermann H₂♂
Das Problem steckt meistens zwischen den Ohren
DRY DRY KISS
H₂ (wenn bei meinen Snipplets nichts anderes angegeben ist Lizenz: WTFPL)
  Mit Zitat antworten Zitat
Furtbichler
(Gast)

n/a Beiträge
 
#8

AW: Referenzen auf ungültige Objekte

  Alt 4. Nov 2011, 07:24
Oder übersehe ich etwas?
Ja, stell dir einfach mal vor, du hast (wie hier schon von stahli skizziert) eben so ein Person-Objekt, welches sich an mehreren anderen Objekten befinden kann (die Person ist Spieler, Schiedsrichter, Sponsor, Depp für Alles )
An einer Stelle im Programm änderst du jetzt den Namen der Person von "Meier" auf "Müller".
Dann wäre es doch schön, wenn alle, die auf die gleiche Person referenzieren auch sofort "Müller" anzeigen und nicht noch den alten Stand mit "Meier".
Das würde ich über Notifications lösen, und wenn ich schon dabei bin, das Freigeben gleich mit. So funktioniert ja auch TDatasource.
  Mit Zitat antworten Zitat
Benutzerbild von stahli
stahli

Registriert seit: 26. Nov 2003
Ort: Halle/Saale
4.352 Beiträge
 
Delphi 11 Alexandria
 
#9

AW: Referenzen auf ungültige Objekte

  Alt 6. Nov 2011, 20:12
Nachtrag zum Beitrag #45, falls es mal jemand nachbaut...
Es ist noch folgende Änderung notwendig:

Delphi-Quellcode:
procedure Tod._RemoveRef(od: Tod);
begin
  if (csDestroying in ComponentState) then
    Exit;
  if not Assigned(FRefList) then
    Exit;
  FRefList.Remove(od);
  if FRefList.Count = 0 then
    FreeAndNil(FRefList);
end;

procedure Tod._RemoveFromRefList(od: Tod);
begin
  if (csDestroying in ComponentState) then
    Exit;
  if Assigned(FRefList) then
    FRefList.Remove(od);
end;
(Ich kann den Beitrag leider nicht mehr editieren.)
Stahli
http://www.StahliSoft.de
---
"Jetzt muss ich seh´n, dass ich kein Denkfehler mach...!?" Dittsche (2004)
  Mit Zitat antworten Zitat
Benutzerbild von stahli
stahli

Registriert seit: 26. Nov 2003
Ort: Halle/Saale
4.352 Beiträge
 
Delphi 11 Alexandria
 
#10

AW: Referenzen auf ungültige Objekte

  Alt 3. Nov 2011, 23:41
Ich hab mal gerade was zusammengehackt... mit Generics ließe sich da sicher noch mehr machen.
Leider scheint mir das doch nicht zu helfen, da ich damit m.E. keine Referenzierungen meiner Objekte untereinander verwalten kann.


Diese GlobaleObjektListe gibt die Instanzen allerdings nicht frei, sondern vergisst diese einfach nur (IPerson => Interface).
Dann sollte es nicht mehr rumsen und die Referenzen sind sauber.
Und dieses Rumgeeiere mit RTTI kannst du dir sparen
Eine solche (ähnliche) Liste habe ich, um auf gültige Objekte prüfen zu können.

Delphi-Quellcode:
function odExist(od: Tod): Boolean;
begin
  if od = nil then
    Exit(False);
  Result := odList.IndexOf(od) >= 0;
end;
Ansonsten will ich aber lieber die Objekte "physisch" vorliegen haben als sie bei jedem Zugriff aus einer Liste herauszusuchen.


Haltet ihr es nicht für ein 'design flaw', wenn ein Objekt von unbestimmt vielen anderen Objekten referenziert wird, während wieder irgend jemand meint, das Objekt auf den Müll werfen zu wollen?
Bei meiner Art zu programmieren (nicht das die besonders toll wäre), kommt so etwas einfach nicht vor. Ich kann mir das nur bei dem OOP-Pendant einer Lookupliste vorstellen. Hier würde ich aber eher die ID speichern (von mir aus der Index in die Liste). Aber selbst da hätte ich ein ungutes Gefühl, denn wenn irgendwer auf ein Objekt zugreift, das ihm von jemandem anderen unterm Ar*** weggezogen wird... also ich weiss nicht, irgendwie "unsauber".
Oder übersehe ich etwas?
Hier unterstelle ich mal, dass Du nicht die Referenzen für problematisch hältst, sondern, dass plötzlich ein Objekt aufgelöst wird, ohne dass vorher alle Referenzen aufgelöst werden...
Aber darum geht es ja gerade. Natürlich verhindere ich z.B., dass ein Spieler gelöscht wird, der in einem Spiel spielt o.ä.
Wenn aber ein Objekt aufgelöst wird will ich erreichen, dass alle Referenzen zuverlässig auf nil gesetzt werden. Das soll weitestgehend automatisch erfolgen (ohne dass ich das in meinem eigentlichen Projekt explizit regeln muss.) Gleiches gilt im übrigen auch für das DataBinding. Wenn ein odEdit meinen Person.FirstName anzeigt und Person aufgelöst wird, darf nix knallen und das edit muss einen Leerstring anzeigen (macht es ja auch ) Auch der Schiedsrichter, Spieler oder Bierverkäufer (nicht Depp!), der die Person referenziert (genau was Sir Rufu später meinte) darf in solch einem Fall nicht problematisch reagieren, sondern soll erkennen, dass die Person nun nil ist. OB die Person gelöscht werden darf, gehört auf ein anderes Blatt.


Solange immer nur Einer gleichzeitig für die Freigabe verantwortlich ist, ist es vollkommen egal, wieviele Referenzen auf ein Objekt zeigt.
Es sollte nur sichergestellt werden, daß keine fremden Referenzen mehr in Umlauf sind, sobald das Objekt freigegeben wird.
Ich habe es jetzt nach dem Observer-Pattern ohne Interface-Einsatz gelöst. Da meine Objekte von einem Experten erstellt werden macht das praktisch für mich keinen Mehraufwand.
Es funktioniert jetzt sehr gut (konnte bisher keine Probleme finden) und auch recht schnell. Die RTTI setze ich aber weiter ein um "PropertyByName" zu realisieren (auch wenn das leider noch etwas langsam ist).

Hier mal ein paar Schnipsel:

Delphi-Quellcode:
Pattern-Auszug:
...
 -> normal // normale Eigenschaften
function {CLASSNAME}.get_[N]: [T];
begin
  Result := F[N];
end;

procedure {CLASSNAME}.set_[N](const Value: [T]);
begin
  if F[N] <> Value then
  begin
    F[N] := Value;
    Changed;
  end;
end;

 -> pointer, pointeras // Wenn Eigenschaften Objekte referenzieren
function {CLASSNAME}.get_[N]: [T];
begin
  Result := F[N];
end;

procedure {CLASSNAME}.set_[N](const Value: [T]);
begin
  if F[N] <> Value then
  begin
    if Assigned(F[N]) then
      F[N]._RemoveRef(Self); // Überwachung abmelden
    F[N] := Value;
    if Assigned(F[N]) then
      F[N]._AddRef(Self); // Überwachung anmelden
    Changed;
  end;
end;
...

Delphi-Quellcode:
destructor Tod.Destroy;
var
  iod: Tod;
begin
  if odRoot = Self then
    odRoot := nil;
  odList.Extract(Self);
  if Assigned(FRefList) then
    begin
      for iod in FRefList do
        begin
          if odExist(iod) then
            begin
              odProp.ClearPointer(iod, Self); // Objekt untersuchen und Referenzen auf Self "nilen"
            end;
        end;
      FreeAndNil(FRefList);
    end;
  odRemoveRefList(Self); // Self aus fremden RefListen löschen
  inherited; // jetzt kann das Objekt freigegeben werden
//
// Es wäre halt schön, wenn die Freigabe auch in Objekten und Variablen erfolgen würde
// die nicht unter der obigen Kontrolle (also in den von mir verwalteten Listen) stehen.
// Das müsste der Compiler dann selbständig verwalten und ich könnte mir das Geraffel sparen.
// Außerdem wäre wünschenswert, dass "Self" auf nil gesetzt wird (wie auch immer das der
// Compiler realisieren könnte).
//
end;

procedure Tod._AddRef(od: Tod);
begin
  if not Assigned(FRefList) then
    FRefList := TObjectList<Tod>.Create(False);
  FRefList.Add(od);
end;

procedure Tod._RemoveRef(od: Tod);
begin
  FRefList.Remove(od);
  if FRefList.Count = 0 then
    FreeAndNil(FRefList);
end;

procedure Tod._RemoveFromRefList(od: Tod);
begin
  if Assigned(FRefList) then
    FRefList.Remove(od);
end;

----------------------

procedure odRemoveRefList(od: Tod);
var
  iod: Tod;
begin
  for iod in odList do
    iod._RemoveFromRefList(od);
end;

function odExist(od: Tod): Boolean;
begin
  if od = nil then
    Exit(False);
  Result := odList.IndexOf(od) >= 0;
end;

ketzerischer Ansatz: wenn niemand den Zeiger auf das Objekt verwenden würde sondern einen Zeiger auf den Zeiger (um den sich der Destruktor des Objekts selbst kümmern muss) gäbe es immer einen gültigen Zugriff und ein nil würde sauber erkannt werden.
Hmm, aber dann dürfte man den Zeiger, der auf den Zeiger zeigt nicht mehr einfach freigeben... Lyncht Ihn!
Stahli
http://www.StahliSoft.de
---
"Jetzt muss ich seh´n, dass ich kein Denkfehler mach...!?" Dittsche (2004)
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 05:44 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 by Thomas Breitkreuz