将默认值(TMyRecord)分配给TMyRecord的变量称为内部调用Finalize,然后将内存清零,就像FillChar那样.例如,在以下问题的答案中已经说过,我确实测试过分配Default()确实会导致调用例如System._FinalizeRecord
Initialize(),Default()和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);
...
Run Code Online (Sandbox Code Playgroud)
我故意使用GetMem()而不是New(),因为据我所知,GetMem()返回的内存不应该自动归零,并且编译器不应该自动调用Initialize.那么在这种情况下,使用默认分配初始化记录不是不安全吗?
在大卫接受的答案中,他正在使用一种漂亮的Clear方法记录类型 如何在Delphi中正确释放包含各种类型的记录? 让我们添加一个
TMyRecord = record
s1, s2, s3 : String;
procedure Clear;
end;
...
procedure TMyRecord.Clear;
begin
Self := Default(TMyRecord);
end;
Run Code Online (Sandbox Code Playgroud)
现在,Clear例程应该完全无法知道记录是否位于堆栈或堆上,并且是否已在其上调用Initialize.
GetMem(pr, SizeOf(TMyRecord));
pr^ := Default(TMyRecord);
Run Code Online (Sandbox Code Playgroud)
上面的代码不正确.但这与使用无关Default().考虑以下代码:
GetMem(pr, SizeOf(TMyRecord));
pr^ := ...;
Run Code Online (Sandbox Code Playgroud)
无论您更换什么,此代码都是错误的....换句话说,您的代码的问题不是使用Default().问题是使用GetMem.在GetMem被调用之后,新分配的内存的内容是不明确的.执行分配时,第一步是完成记录的当前内容.由于这些内容定义不明确,任何事情都可能发生.
在动态分配包含托管类型的记录时,您应该使用New.如果您只是必须GetMem在这种情况下使用,则需要负责确保记录中的管理成员在随后使用记录之前进行适当的初始化.
所以在我看来你给了你的问题错误的标题.代替
使用
Default()赋值来初始化记录是否安全?
这个问题应该是标题
在记录初始化之前对记录做任何事情是否安全?