And*_*rew 10 delphi free null procedure
如果你看一下FreeAndNil程序的代码,你会看到:
procedure FreeAndNil(var Obj);
var
Temp: TObject;
begin
Temp := TObject(Obj);
Pointer(Obj) := nil;
Temp.Free;
end;
Run Code Online (Sandbox Code Playgroud)
它们分配Nil给对象引用的原因是什么,只有在它被破坏之后?为什么反之亦然?
Dav*_*nan 11
我可以想到这样做的两个原因,这两个原因似乎都没有引人注目.
原因1:保证在引发异常时将引用设置为nil
实施实现了这一点.如果析构函数引发,则引用仍设置为nil.另一种方法是使用finally块:
try
TObject(Obj).Free;
finally
TObject(Obj) := nil;
end;
Run Code Online (Sandbox Code Playgroud)
这方面的缺点是性能.特别是在x86 try/finally上,a有点贵.在这样一个基本的例程中,谨慎的做法是避免这种费用.
为什么我不惜一切代价都不愿意这样做?好吧,一旦析构函数开始失败,你也可以放弃.您无法再清楚地了解您的计划的状态.你无法分辨失败的程度以及你的程序处于什么状态.我认为,面对一个提升的析构函数,正确的行动过程是终止进程.
原因2:确保其他线程可以检测到对象正在被销毁
这又实现了,但它没有实际用途.是的,您可以测试是否已分配参考.但那又怎样?另一个线程无法在没有同步的情况下调用对象上的方法.你所能做的就是了解对象是否还活着.如果是这样的话,为什么在析构函数运行之前或之后这个状态发生了变化?
因此,虽然我提出这个可能的原因,我无法相信Embarcadero的任何人都被这个论点所左右.
Dis*_*ned 10
大卫的第二个原因有一个变化,它更引人注目.虽然有人可能会争辩说,如果适用,还有其他问题需要解决.
原因3:确保同一线程上的事件处理程序可以检测到对象正在被销毁
这是一个炮制的假设示例:
TOwner.HandleCallback;
begin
if Assigned(FChild) then
FChild.DoSomething;
end;
TChildClass.Destroy;
begin
if Assigned(FOnCallback) then FOnCallback;
inherited Destroy;
end;
Run Code Online (Sandbox Code Playgroud)
现在,如果TOwner打电话:
FChild.Free;
FChild := nil;
Run Code Online (Sandbox Code Playgroud)
FChild将被要求DoSomething在其销毁周期的中间.一个灾难的秘诀.实施FreeAndNil整齐地避免了这一点.
是的,您可能会认为在销毁期间发射回调事件是危险的,但它确实有其好处.Delphi/VCL代码中的例子很少.特别是如果你扩大关注范围以包括调用多态方法 - 这也将破坏序列的各个方面置于你的控件之外.
现在我必须指出,我不知道Delphi库代码中可能出现此问题的任何特定情况.但是VCL的某些部分存在一些复杂的循环依赖关系.因此,如果将实现更改为SysUtils中更明显的选择会导致一些令人不快的意外,我不会感到惊讶.