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 niling the field FMyObject.
FreeAndNil frees to object pointed to, and nils 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