Ik denk dat ik weet waar het probleem zit, en ik heb 't pas nog 2x uitgelegd wat betreft FreeAndNil, maar hier zal ik 't nog een keer duidelijk uitleggen, kan ik dit mooi linken als het nog een keer gevraagd wordt :
Free controleert of Self nil is, zo ja, dan stopt ie met proberen te destroyen. Waarom kan je uberhaupt Free aanroepen op een nil-object? Dit heeft te maken met de manier waarop objecten worden opgeslagen, in feite wordt het na compilatie een stel functies die, semi-onzichtbaar voor de programmeur, een Self parameter meekrijgen die wijst naar de data voor de desbetreffende instantie (de data van het object wat jij in je code geCreate hebt). Op deze manier maak je van een Object Orientated stuk code in feite een lineair geheel, wat handig is voor de CPU, die helemaal geen kaas gegeten heeft van OO . Die Self parameter zie je dus niet in je parameterlijst staan, maar is wel te benaderen vanuit je code... "compiler magic" zullen we 't maar noemen...
Je kan dus een functie van een nil-object aanroepen, en dit gaat ook goed, maar het gedraagt zich als een class procedure (alleen wordt niet afgevangen door de compiler), dwz: je kan geen variabelen (beter gezegd: instantiedata) aanspreken, dan wordt namelijk geprobeerd die nil-data uit te lezen, wat een fout genereerd. Echter, andere code is geen probleem (zoals de 'if Self <> nil' code). Tot zover dus de uitleg over waarom het mogelijk is en hoe 't werkt, mogelijk dat ik hier fouten in heb gemaakt (ik ben geen deel van het Delphi-compiler-programmeer-team tenslotte ), maar dat moet je me dan maar vergeven.
Nu een mogelijke verklaring voor jouw probleem: als je een variabele aanmaakt van een TObject (en descendants uiteraard) wordt dat achter de schermen opgeslagen als een pointer die wijst naar de bovengenoemde instantiedata en de verwijzingen naar de bijbehorende functies (ik meen dat men dat de 'Virtual Method Table' noemt). Als je op een bestaand object Free aanroept wordt deze netjes vrijgegeven, echter, je variabele (de pointer) blijft nog steeds wijzen naar dit stukje geheugen, ondanks dat dat geheugen niet meer van jou is. Als je daarna dus nog een keer Free aanroept geeft ie als Self die pointer mee, wat niet gelijk is aan nil (!!), en dus zal Free Destroy aanroepen, wat op zijn beurt een Access Violation geeft omdat Windows je vrolijk verteld dat dat geheugen niet meer jouw eigendom is (en gelukkig maar, anders crash je niet alleen je eigen, maar ook andere programma's )
Dit is tegelijkertijd de reden dat ik FreeAndNil gebruik, hetzelfde kan je bereiken door na de eerste Free de variabele de nil-waarde toe te wijzen (maar FreeAndNil is korter ), dan kan de nil wel worden gedetecteerd de tweede keer en zal alles goed gaan...
[Edit]
Ter aanvulling, dit geeft nog een extra verklaring voor jouw probleem, net even getest:
Code:
var
pTest: TObject;
begin
// Dit gaat grandioos fout! Waarom? Omdat pTest ongeinitialiseerd is, en
// dus zal deze 'pointer' een random waarde bevatten, net zoals eigenlijk
// alle andere variabelen die je geen beginwaarde toekent (op globale
// variabelen na, die cleared de compiler voor je). In dit geval zal de
// compiler je ook een Warning geven...
pTest.Free();
// Dit is dus wel goed en geeft geen problemen:
pTest := nil;
pTest.Free();
end;
Ook als pTest onderdeel is van een class wordt deze volgens mij door de compiler gecleared (nil gemaakt dus). In elk geval kan het nooit kwaad eerst een nil, 0, '' of wat dan ook toe te kennen aan een variabele voordat je ermee gaat werken, dit verzekerd je ervan dat je geen foute waarden krijgt...
Bookmarks