【发布时间】:2014-12-03 14:07:39
【问题描述】:
将 Default(TMyRecord) 分配给 TMyRecord 的变量据说首先在内部调用 Finalize,然后像 FillChar 那样将内存清零。例如,这在以下问题的答案中已经说过,并且我确实测试了分配 Default() 确实会导致调用例如 System._FinalizeRecord
How to properly free records that contain various types in Delphi at once?
Difference between Initialize(), Default() and FillChar()
我的问题是,像这样初始化记录是否总是安全的,即使在 Delphi 没有自动对其调用 Initialize 的情况下?对我来说,在未初始化的记录变量上调用 Finalize 似乎没有意义。在初始化之前,必须假定内存中包含随机垃圾。在这种情况下,我对托管类型特别感兴趣,它们是指向动态分配内存的指针,Finalize 例程应该通过减少它们的引用计数等来完成它们。在许多情况下,Delphi 会自动生成对 Initialize 的调用,以确保其托管类型保持托管状态。但并非总是如此。
这是一个说明问题案例的示例。正如在下面的答案中所评论的,您不应该使用 GetMem 来分配包含此类托管类型的记录,但我们假设有人这样做了,然后尝试使用 Default() 赋值作为初始化
type
TMyRecord = record
s1, s2, s3 : String;
end;
PMyRecord = ^TMyRecord;
var
pr : PMyRecord;
begin
GetMem(pr, SizeOf(TMyRecord));
pr^ := Default(TMyRecord);
...
我故意使用 GetMem() 而不是 New(),因为据我所知,GetMem() 返回的内存不应自动归零,并且编译器不应插入对 Initialize 的自动调用。那么在这种情况下,使用默认赋值来初始化记录会不会不安全?
在大卫在这里接受的答案中,他对记录类型使用了一种漂亮的 Clear 方法 How to properly free records that contain various types in Delphi at once? 让我们添加一个
TMyRecord = record
s1, s2, s3 : String;
procedure Clear;
end;
...
procedure TMyRecord.Clear;
begin
Self := Default(TMyRecord);
end;
现在,Clear 例程应该完全无法知道记录是否位于堆栈或堆上,并且是否已对其调用 Initialize。
【问题讨论】:
标签: delphi