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.
It is never OK to call
Dispose()on anilpointer variable. The RTL expects the variable to point at valid memory allocated withNew(), and so will unconditionally try to finalize whatever data/object is being pointed at. Passing in a pointer variable that isnilleads to undefined behavior and will likely crash.Dispose(nil)is effectively a no-op. The compiler knows thenilliteral can't possibly point at a data type that needs to be finalized, so it doesn't need to callSystem._Dispose(), hence it callsSystem._FreeMem()instead (why it calls anything at all, I don't know).System._FreeMem()allowsnilas input, it will simply exit without doing anything. However,System._Dispose()on a pointer variable does not allownilas input (and never has).