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 anilpointer.
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).
