In the following example:
program DisposeProblem;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils;
type
Person = record
name: string;
age: Integer;
end;
var
p: ^Person;
begin
p := nil;
Dispose(nil); // OK
Dispose(p); // AV
end.
Why is the first Dispose()
call OK, while the second causes an access violation error? When I step through the code, the first Dispose()
calls System._FreeMem()
, while the second calls System._Dispose()
, but I don't understand why this is the case. I would like to understand this behavior so I can know when it is safe to call Dispose()
on a nil
pointer.
CodePudding user response:
I would like to understand this behavior so I can know when it is safe to call
Dispose()
on anil
pointer.
It is never OK to call Dispose()
on a nil
pointer variable. The RTL expects the variable to point at valid memory allocated with New()
, and so will unconditionally try to finalize whatever data/object is being pointed at. Passing in a pointer variable that is nil
leads to undefined behavior and will likely crash.
Dispose(nil)
is effectively a no-op. The compiler knows the nil
literal can't possibly point at a data type that needs to be finalized, so it doesn't need to call System._Dispose()
, hence it calls System._FreeMem()
instead (why it calls anything at all, I don't know).
System._FreeMem()
allows nil
as input, it will simply exit without doing anything. However, System._Dispose()
on a pointer variable does not allow nil
as input (and never has).