Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/delphi/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Delphi中使用Default()赋值来初始化记录变量安全吗?_Delphi - Fatal编程技术网

在Delphi中使用Default()赋值来初始化记录变量安全吗?

在Delphi中使用Default()赋值来初始化记录变量安全吗?,delphi,Delphi,将DefaultTMyRecord分配给TMyRecord的一个变量被认为是在内部先调用Finalize,然后像FillChar那样将内存归零。例如,在对以下问题的回答中已经提到了这一点,我测试过分配默认值确实会导致调用示例系统 我的问题是,即使在Delphi没有自动调用initialize的情况下,这样初始化记录总是安全的吗?对我来说,对未初始化的记录变量调用Finalize似乎没有意义。在初始化之前,必须假定内存包含随机垃圾。在本例中,我特别感兴趣的是托管类型,它是指向动态分配内存的指针,F

将DefaultTMyRecord分配给TMyRecord的一个变量被认为是在内部先调用Finalize,然后像FillChar那样将内存归零。例如,在对以下问题的回答中已经提到了这一点,我测试过分配默认值确实会导致调用示例系统

我的问题是,即使在Delphi没有自动调用initialize的情况下,这样初始化记录总是安全的吗?对我来说,对未初始化的记录变量调用Finalize似乎没有意义。在初始化之前,必须假定内存包含随机垃圾。在本例中,我特别感兴趣的是托管类型,它是指向动态分配内存的指针,Finalize例程应该通过减少它们的引用计数等来完成。在许多情况下,Delphi会自动生成初始化调用,以确保其托管类型保持托管状态。但并非总是如此

这里有一个例子说明了一个有问题的案例。正如在下面的答案中所评论的,您不应该使用GetMem来分配包含这样的托管类型的记录,但是让我们假设有人这样做了,然后尝试使用默认分配作为初始化

type
  TMyRecord = record
    s1, s2, s3 : String;
  end;
  PMyRecord = ^TMyRecord;

var
  pr : PMyRecord;

begin
  GetMem(pr, SizeOf(TMyRecord)); 
  pr^ := Default(TMyRecord);
...
我故意使用GetMem而不是New,因为据我所知,GetMem返回的内存不应该自动归零,编译器也不应该插入初始化的自动调用。所以在这种情况下,使用默认分配初始化记录不是不安全吗

在David接受的答案中,他对记录类型使用了一种非常清晰的方法 让我们加上这个

  TMyRecord = record
    s1, s2, s3 : String;
    procedure Clear;
  end;
...
procedure TMyRecord.Clear;
begin
  Self := Default(TMyRecord);
end;
现在,Clear例程应该完全无法知道记录是否位于堆栈或堆上,是否已对其调用Initialize

所以在这种情况下,使用默认分配初始化记录不是不安全吗

是的,那是不安全的。这将最终确定垃圾,垃圾很容易崩溃,甚至更糟

如果需要初始化内存,请使用initialize方法,或者编写一些编译器将代表您隐式执行的内容

现在,Clear例程应该完全无法知道记录是否位于堆栈或堆上,是否已对其调用Initialize

该代码假定已对其调用了Initialize,并将该职责转移给了调用方。这对我来说很有意义。必须处理未初始化内存的代码是例外,而不是常规代码

换句话说,这些代码并不是设计用来做你想做的事情的。这并不意味着代码有任何缺陷。它擅长于它的设计目的

GetMem(pr, SizeOf(TMyRecord));
pr^ := Default(TMyRecord);
所以在这种情况下,使用默认分配初始化记录不是不安全吗

是的,那是不安全的。这将最终确定垃圾,垃圾很容易崩溃,甚至更糟

如果需要初始化内存,请使用initialize方法,或者编写一些编译器将代表您隐式执行的内容

现在,Clear例程应该完全无法知道记录是否位于堆栈或堆上,是否已对其调用Initialize

该代码假定已对其调用了Initialize,并将该职责转移给了调用方。这对我来说很有意义。必须处理未初始化内存的代码是例外,而不是常规代码

换句话说,这些代码并不是设计用来做你想做的事情的。这并不意味着代码有任何缺陷。它擅长于它的设计目的

GetMem(pr, SizeOf(TMyRecord));
pr^ := Default(TMyRecord);
上述代码不正确。但这与使用默认值无关。考虑这个代码:

GetMem(pr, SizeOf(TMyRecord));
pr^ := ...;
无论您更换什么,此代码都是不正确的。。。具有换句话说,代码的问题不是使用默认值。问题在于GetMem的使用。调用GetMem后,新分配内存的内容定义不清。执行赋值时,第一步是完成记录的当前内容。由于这些内容定义不清,任何事情都有可能发生

动态分配包含托管类型的记录时,您需要使用新的。如果在此场景中必须使用GetMem,那么您需要负责确保记录中的托管成员在后续使用记录之前进行了适当的初始化

所以在我看来,你给你的问题的标题是错误的。而不是

使用默认分配初始化记录是否安全

这个问题应该有个标题

在记录初始化之前对其执行任何操作是否安全

上述代码不正确。但这与使用默认值无关。考虑这个代码:

GetMem(pr, SizeOf(TMyRecord));
pr^ := ...;
无论您更换什么,此代码都是不正确的。。。具有换句话说 换句话说,代码的问题不是使用默认值。问题在于GetMem的使用。调用GetMem后,新分配内存的内容定义不清。执行赋值时,第一步是完成记录的当前内容。由于这些内容定义不清,任何事情都有可能发生

动态分配包含托管类型的记录时,您需要使用新的。如果在此场景中必须使用GetMem,那么您需要负责确保记录中的托管成员在后续使用记录之前进行了适当的初始化

所以在我看来,你给你的问题的标题是错误的。而不是

使用默认分配初始化记录是否安全

这个问题应该有个标题

在记录初始化之前对其执行任何操作是否安全


有人可能会说,要补充的是,AllocMem分配的内存为零呢?但是,对于GetMem和AllocMem,您使用的是FreeMem,它不会最终确定,而对于New,您使用的是Dispose,它会最终确定。感谢您富有洞察力的评论,但我确实想特别询问一下如何使用默认分配来初始化记录。对我来说,这似乎是个坏主意,因为在某些情况下,它会有效地调用未初始化的垃圾。我猜在这种情况下,你根本不理解我的答案。我想不出比这更好的表达方式了。你对我的回答的评论清楚地表明,你对这些问题的理解是错误的。我不能强迫你纠正这一点。启发我的问题是默认分配给我的建议是一种无需头脑的初始化函数,它总是可以被记录在一个记录上,而不必考虑记录中的内容,托管类型是什么,当Delphi自动生成一个隐式的初始化调用时,Initialize甚至做了什么,等等,为什么会有人想要这样的事情呢?例如,帮助某些具有C语言背景的程序员避免学习所有这些东西。毕竟,它只是一个结构,对吗?不,不是你接受了另一个答案。你告诉我我没有回答你的问题。我并不特别想和你争论。我知道我自己的意见。我觉得没有热情和你争论并试图改变你。如果你想听我的建议,我很乐意给你。但在我看来,你已经表明你不同意我的观点,也不想听我的意见。很好。只是想补充一下,有人可能会说,AllocMem分配的内存是零,那怎么办?但是,对于GetMem和AllocMem,您使用的是FreeMem,它不会最终确定,而对于New,您使用的是Dispose,它会最终确定。感谢您富有洞察力的评论,但我确实想特别询问一下如何使用默认分配来初始化记录。对我来说,这似乎是个坏主意,因为在某些情况下,它会有效地调用未初始化的垃圾。我猜在这种情况下,你根本不理解我的答案。我想不出比这更好的表达方式了。你对我的回答的评论清楚地表明,你对这些问题的理解是错误的。我不能强迫你纠正这一点。启发我的问题是默认分配给我的建议是一种无需头脑的初始化函数,它总是可以被记录在一个记录上,而不必考虑记录中的内容,托管类型是什么,当Delphi自动生成一个隐式的初始化调用时,Initialize甚至做了什么,等等,为什么会有人想要这样的事情呢?例如,帮助某些具有C语言背景的程序员避免学习所有这些东西。毕竟,它只是一个结构,对吗?不,不是你接受了另一个答案。你告诉我我没有回答你的问题。我并不特别想和你争论。我知道我自己的意见。我觉得没有热情和你争论并试图改变你。如果你想听我的建议,我很乐意给你。但在我看来,你已经表明你不同意我的观点,也不想听我的意见。那很好。