Validität feststellen
-
- Beiträge: 200
- Registriert: So 11. Jul 2010, 18:39
- OS, Lazarus, FPC: Linux
- CPU-Target: 64 Bit
- Wohnort: Wien
- Kontaktdaten:
Validität feststellen
Ist es eigentlich möglich (und wenn ja: wie?) festzustellen, ob eine Objektvariable auf ein gültiges Objekt zeigt, bevor man es freigibt?
Ceterum censeo computatores per Pascal docendos esse.
-
- Beiträge: 3444
- Registriert: Mo 11. Sep 2006, 10:24
- OS, Lazarus, FPC: svn (Window32, Linux x64, Linux ARM (QNAP) (cross+nativ)
- CPU-Target: X32 / X64 / ARMv5
- Wohnort: Krefeld
Re: Validität feststellen
Nö. Nach dem Freigeben kann der Pointer auf irgendwas zeigen. Daran kann man dann auch nichts mehr erkennen.diogenes hat geschrieben:Ist es eigentlich möglich (und wenn ja: wie?) festzustellen, ob eine Objektvariable auf ein gültiges Objekt zeigt, bevor man es freigibt?
Zu diesem Zweck gibt es "FreeAndNIL", das den Pointer auf das freigegeben Objekt nullt. Aber nur diesen Pointer, alle anderen, wohin man die Objekt-referenz irgendwann einmal kopiert hat bleiben ungleich NIL und ungültig.
Nowas geht sinnvoll nur in C# und ähnlichen Sprachen mit Garbage-Control.
-Michael
-
- Beiträge: 200
- Registriert: So 11. Jul 2010, 18:39
- OS, Lazarus, FPC: Linux
- CPU-Target: 64 Bit
- Wohnort: Wien
- Kontaktdaten:
Re: Validität feststellen
FreeAndNIL ist mir bekannt. Danke jedenfalls für diese Information, die zwar enttäuschend ist, aber immerhin lernt man auch dabei was. Einen SIGSEGV könnt' man aber mit try ... except/finally ... end abfangen, oder?
Ceterum censeo computatores per Pascal docendos esse.
- m.fuchs
- Lazarusforum e. V.
- Beiträge: 2809
- Registriert: Fr 22. Sep 2006, 19:32
- OS, Lazarus, FPC: Winux (Lazarus 2.0.10, FPC 3.2.0)
- CPU-Target: x86, x64, arm
- Wohnort: Berlin
- Kontaktdaten:
Re: Validität feststellen
Warum willst du das prüfen? Ein Aufruf von .Free bei einem ungültigen Objekt schadet doch nicht.diogenes hat geschrieben:Ist es eigentlich möglich (und wenn ja: wie?) festzustellen, ob eine Objektvariable auf ein gültiges Objekt zeigt, bevor man es freigibt?
Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de
Re: Validität feststellen
m.fuchs hat geschrieben: Warum willst du das prüfen? Ein Aufruf von .Free bei einem ungültigen Objekt schadet doch nicht.
Ach ja? Aber eine Zugriffsverletzung gibt's schon, oder?
Code: Alles auswählen
var Sl:TStringList;
begin
Sl:=TStringList.Create;
Sl.Free;
Sl.Free;
end;
Wenn's nil ist geht das:
Code: Alles auswählen
var Sl:TStringList;
begin
Sl:=TStringList.Create;
FreeAndNil(Sl);
Sl.Free;
end;
- m.fuchs
- Lazarusforum e. V.
- Beiträge: 2809
- Registriert: Fr 22. Sep 2006, 19:32
- OS, Lazarus, FPC: Winux (Lazarus 2.0.10, FPC 3.2.0)
- CPU-Target: x86, x64, arm
- Wohnort: Berlin
- Kontaktdaten:
Re: Validität feststellen
Ah, Irrtum meinerseits. Mir war so, als ob .Free eine besondere Magie hätte, die solche Fälle abfängt. Aber das gilt natürlich nur, wenn die Referenz korrekt auf nil gesetzt wird.
Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de
-
- Beiträge: 200
- Registriert: So 11. Jul 2010, 18:39
- OS, Lazarus, FPC: Linux
- CPU-Target: 64 Bit
- Wohnort: Wien
- Kontaktdaten:
Re: Validität feststellen
Eben. Deswegen meine Fragen.
Ceterum censeo computatores per Pascal docendos esse.
-
- Beiträge: 586
- Registriert: Mi 25. Mär 2009, 21:12
- OS, Lazarus, FPC: Laz trunk / fpc latest release / Win and other
- CPU-Target: mostly 32 bit
Re: Validität feststellen
Nein einen Test gibt es nicht.
Man könnte zwar bestimmte Kriterien zu prüfen suchen (Speicher allocatiert? fpc interne Strukturen), aber sicher ist es trotzdem nicht.
1) Ein anderes Objekt koennte mittlerweile an diesem platz seien
2) Das alte Objekt ist zwar freigegeben, aber der Speicher noch nicht (oder nur teilweise) überschrieben). Dann sieht es zunaechst so aus als ob es noch da waere.
Wenn du mehrere variablen hast die auf das selbe Objekt zeigen, dann kannst du:
1) TComponent.FreeNotification
2) Andere Objecte, definiere selbst ein event (event liste) das bei Freigabe aufgerufen wird
1&2) Und dann kann fuer jede variable ein event listener eingetragen werden, und das Objekt zerstoeren.
3) Implementiere eine RefCounted Loesung (TRefCountedObject ist in lazutils IIRC)
Man könnte zwar bestimmte Kriterien zu prüfen suchen (Speicher allocatiert? fpc interne Strukturen), aber sicher ist es trotzdem nicht.
1) Ein anderes Objekt koennte mittlerweile an diesem platz seien
2) Das alte Objekt ist zwar freigegeben, aber der Speicher noch nicht (oder nur teilweise) überschrieben). Dann sieht es zunaechst so aus als ob es noch da waere.
Wenn du mehrere variablen hast die auf das selbe Objekt zeigen, dann kannst du:
1) TComponent.FreeNotification
2) Andere Objecte, definiere selbst ein event (event liste) das bei Freigabe aufgerufen wird
1&2) Und dann kann fuer jede variable ein event listener eingetragen werden, und das Objekt zerstoeren.
3) Implementiere eine RefCounted Loesung (TRefCountedObject ist in lazutils IIRC)
-
- Lazarusforum e. V.
- Beiträge: 3178
- Registriert: Di 22. Jul 2008, 19:27
- OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
- CPU-Target: 32bit x86 armhf
- Wohnort: Köln
- Kontaktdaten:
Re: Validität feststellen
Bei Objekten ist diese Regel allgemein üblich:
Ist die Adresse gleich nil, ist kein Objekt vorhanden. Ist die Adresse eine andere, geht man davon aus, dass ein Objekt existiert.
Im Programmfluss sieht das so aus:
Damit ist das martin_frb angesprochene Problem bei verknüpften Objekten noch nicht ganz gelöst. Wird ein Objekt freigegeben, müssen -- wie er ausgeführt hat -- auch die in anderen Objekten abgelegten Referenzen gelöscht (oder auf nil gesetzt) werden (wenn nil entsprechend behandelt wird).
Ist die Adresse gleich nil, ist kein Objekt vorhanden. Ist die Adresse eine andere, geht man davon aus, dass ein Objekt existiert.
Im Programmfluss sieht das so aus:
Code: Alles auswählen
procedure myproc;
var
o: TObject;
begin
// 1. o hat einen unbekannten Wert, da die Variable in Pascal nicht initialisiert wird.
// 2. Der Variablen einen _bekannten_ Wert zuweisen.
o := nil; // nil = kein Objekt. Jetzt kann man auf diesen Wert prüfen.
o := TObject.Create; // ein Objekt erzeugen. Falls dies nicht erfolgreich ist, wird eine Exception ausgelöst und o muss wie unter 1. behandelt werden.
// 3. Objekt freigeben
o.Destroy; // hier _muss_ das Objekt existieren
// 4. o auf einen bekannten Wert (nil) setzen.
o := nil; // jetzt kann wieder auf nil überprüft werden.
// eine Überprüfung kann so aussehen:
if o <> nil then
// oder alternativ (beide Varianten sind äquivalent)
if Assigned(o) then
o.myfunc;
// Free als Alternative zu Destroy:
o := TObject.Create;
o.Free; // Objekt freigeben
o := nil;
// Die Funktion Free überprüft, ob das aktuelle Objekt (Self) ungleich nil ist. Nur dann wird auch der Destruktor aufgerufen.
o.Free; // Objekt wird nicht freigeben, da o = nil ist. Hier tritt keine Access Violation auf
// Die Funktion FreeAndNil() nichts anderes als das Folgende (nur als fertige Funktion):
o.Free;
o := nil;
end;
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein
-
- Beiträge: 2013
- Registriert: Do 16. Okt 2008, 10:22
- OS, Lazarus, FPC: Linux,Windows,FreeBSD,(MSEide+MSEgui 4.6,git master FPC 3.0.4,fixes_3_0)
- CPU-Target: x86,x64,ARM
Re: Validität feststellen
Falls es euch interessiert, MSEgui hat dafür einen Mechanismus in tmsecomponent mit iobjectlink, implementiert durch tobjectlinker. Eine tmsecomponent Variable gesetzt mit tmsecomponent.setlinkedvar() wird automatisch nil gesetzt beim Freigeben des Objektes. Der iobjectlink Nachkomme ievent wird zudem zur Kommunikation unter den verbundenen Objekten verwendet, siehe mseclasses.pas.Socke hat geschrieben: Damit ist das martin_frb angesprochene Problem bei verknüpften Objekten noch nicht ganz gelöst. Wird ein Objekt freigegeben, müssen -- wie er ausgeführt hat -- auch die in anderen Objekten abgelegten Referenzen gelöscht (oder auf nil gesetzt) werden (wenn nil entsprechend behandelt wird).
http://gitorious.org/mseide-msegui/msei ... lasses.pas
Code: Alles auswählen
objecteventty = (oe_destroyed,oe_connect,oe_disconnect,
oe_changed,oe_designchanged,
oe_activate,oe_deactivate,oe_fired,oe_dataready,
oe_bindfields,oe_releasefields);
objectlinkeventty = procedure(const sender: tobject;
const event: objecteventty) of object;
iobjectlink = interface(inullinterface)
procedure link(const source,dest: iobjectlink; valuepo: pointer = nil;
ainterfacetype: pointer = nil; once: boolean = false);
procedure unlink(const source,dest: iobjectlink; valuepo: pointer = nil);
//source = 1 -> dest destroyed
procedure objevent(const sender: iobjectlink; const event: objecteventty);
function getinstance: tobject;
end;
[...]
tobjectevent = class;
ievent = interface(iobjectlink)
procedure receiveevent(const event: tobjectevent);
end;
objeventstatety = (oes_islinked,oes_modaldeferred);
objeventstatesty = set of objeventstatety;
tobjectevent = class(tmseevent,iobjectlink)
private
finterface: pointer; //ievent;
procedure link(const source,dest: iobjectlink; valuepo: pointer = nil;
ainterfacetype: pointer = nil; once: boolean = false);
procedure unlink(const source,dest: iobjectlink; valuepo: pointer = nil);
procedure objevent(const sender: iobjectlink; const event: objecteventty);
function getinstance: tobject;
protected
fstate: objeventstatesty;
fmodallevel: integer;
public
constructor create(akind: eventkindty; const dest: ievent;
const modaldefer: boolean = false);
destructor destroy; override;
procedure deliver;
property modallevel: integer read fmodallevel;
end;