I want to pass an object A to a second object B, have B do some processing and finally release A in case it's not needed anymore. A watered down version is given below.
program Project6;
{$APPTYPE CONSOLE}
uses
SysUtils;
type
TMyObject = class(TObject)
public
FField1: string;
FField2: string;
end;
TBigObject = class(TObject)
public
FMyObject: TMyObject;
procedure Bind(var MyObject: TMyObject);
procedure Free();
end;
procedure TBigObject.Bind(var MyObject: TMyObject);
begin
FMyObject := MyObject;
end;
procedure TBigObject.Free;
begin
FreeAndNil(FMyObject);
Destroy();
end;
var
MyObject: TMyObject;
BigObject: TBigObject;
begin
try
MyObject := TMyObject.Create();
BigObject := TBigObject.Create();
BigObject.Bind(MyObject);
BigObject.Free();
if (Assigned(MyObject)) then begin
WriteLn('Set MyObject free!');
MyObject.Free();
end;
ReadLn;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
(Never mind the awful design.) Now, what I don't understand is why FreeAndNil actually does free MyObject, yet Assigned(MyObject)
is evaluated to true (giving an AV at MyObject.Free()
).
Could someone please help enlighten me?
MyObject
is a different variable from the field FMyObject
. And you're only nil
ing the field FMyObject
.
FreeAndNil
frees to object pointed to, and nil
s the variable you passed in. It doesn't magically discover and nil
all other variables that point to the object you freed.
FreeAndNil(FMyObject);
does the same thing as:
object(FMyObject).Free();
FMyObject=nil;
(Technically this is not entirely correct, the cast to object is a reinterpret cast due to the untyped var
parameter, but that's not relevant here)
And that obviously only modifies FMyObject
and not MyObject
Oh I just noticed that you're hiding the original Free
method? That's insane. FreeAndNil
still uses the original Free
. That doesn't hit you in your example because you call Free
on a variable with the static type TBigObject
and not FreeAndNil
. But it's a receipt for disaster.
You should instead override the destructor Destroy
.
The reason is simple, you nil one reference but not the other. Consider this example:
var
Obj1, Obj2: TObject;
begin
Obj1 := TObject.Create;
Obj2 := Obj1;
FreeAndNil(Obj1);
// Obj1 is released and nil, Obj2 is non-nil but now points to undefined memory
// ie. accessing it will cause access violations
end;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With