Assigning Default(TMyRecord) to a variable of TMyRecord is said to internally call first Finalize and then zero out the memory like FillChar would. This has been said in answers to the following questions, for example, and I did test that assigning Default() does indeed cause a call to for example System._FinalizeRecord
How to properly free records that contain various types in Delphi at once?
Difference between Initialize(), Default() and FillChar()
My question is, is it always safe to initialize records like that, even in cases where Delphi hasn't automatically called Initialize on it? To me it doesn't seem to make sense to call Finalize on an uninitialized record variable. Before initialization, the memory must be assumed to contain random garbage. In this case, I am particularly interested in managed types which are pointers to dynamically allocated memory, which the Finalize routine should finalize by decreasing their reference counts and so on. In many cases, Delphi automatically generates calls to Initialize to make sure its managed types stay managed. But not always.
Here is an example that illustrates a problematic case. As commented in answers below, you should not use GetMem for allocating records containing managed types like this, but let's just assume someone did, and then tried to use Default() assignment as initialization
type
TMyRecord = record
s1, s2, s3 : String;
end;
PMyRecord = ^TMyRecord;
var
pr : PMyRecord;
begin
GetMem(pr, SizeOf(TMyRecord));
pr^ := Default(TMyRecord);
...
I am deliberately using GetMem() instead of New(), because as far as I know, the memory returned by GetMem() should not be automatically zeroed and no automatic call to Initialize should have been inserted by the compiler. So in this case, wouldn't it be unsafe to use Default assignment for initializing the record?
In David's accepted answer here he is using a nifty Clear method for the record type How to properly free records that contain various types in Delphi at once? Let's add that one
TMyRecord = record
s1, s2, s3 : String;
procedure Clear;
end;
...
procedure TMyRecord.Clear;
begin
Self := Default(TMyRecord);
end;
Now, that Clear routine should have absolutely no way of knowing if the record is sitting on the stack or heap, and Initialize has been called on it, or not.