Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/delphi/9.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/visual-studio-code/3.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 为什么我应该在析构函数中使用Free和notfreeandnil?_Delphi_Destructor_Delphi 2007 - Fatal编程技术网

Delphi 为什么我应该在析构函数中使用Free和notfreeandnil?

Delphi 为什么我应该在析构函数中使用Free和notfreeandnil?,delphi,destructor,delphi-2007,Delphi,Destructor,Delphi 2007,我已经读过了,但仍然不明白为什么我不能在类析构函数中使用这个方法?谁能解释一下 更新:我认为来自的评论对我非常有用。链接显示,如何处理这一问题并不明显,主要是口味问题。此外,FreeAndInvalidate方法也很有用 问题是有那么多 似乎把FreeAndNil当作魔法 子弹会杀死那个神秘的人 撞车龙。如果在中使用FreeAndNil() 析构函数似乎解决了一个碰撞问题 或其他内存损坏问题, 那么你应该更深入地挖掘 真正的原因。当我看到这个的时候 我问的第一个问题是,为什么 之后正在访问的实例

我已经读过了,但仍然不明白为什么我不能在类析构函数中使用这个方法?谁能解释一下

更新:我认为来自的评论对我非常有用。链接显示,如何处理这一问题并不明显,主要是口味问题。此外,FreeAndInvalidate方法也很有用

问题是有那么多 似乎把FreeAndNil当作魔法 子弹会杀死那个神秘的人 撞车龙。如果在中使用FreeAndNil() 析构函数似乎解决了一个碰撞问题 或其他内存损坏问题, 那么你应该更深入地挖掘 真正的原因。当我看到这个的时候 我问的第一个问题是,为什么 之后正在访问的实例字段 那个实例被破坏了?那个 通常指向设计问题

它认为它隐藏了你真正的问题。这必须意味着您的代码正在访问已经销毁的对象(调用析构函数)的属性/字段/方法。因此,你不应该用FreeAndNil隐藏真正的问题,而应该真正解决潜在的问题

如果在SomeObject的析构函数中使用FreeAndNil PropertyA,下面的代码不会崩溃。但它隐藏了一个真正的问题,即某个对象在被销毁后被使用。最好解决这个设计问题(访问被破坏的对象),而不是隐藏它

SomeObject.Free;  // Destructor called
if Assigned(SomeObject.PropertyA) then  // SomeObject is destroyed, but still used
  SomeObject.PropertyA.Method1;  
编辑

另一种情况是,如果不使用FreeAndNil,代码也不会崩溃。因为即使对象被破坏,内存也可能无法重用,所有结构都可能处于正常状态。如果使用Free来销毁PropertyA而不是FreeAndNil,那么上面的代码甚至可以毫无问题地运行

如果FreeAndNil用于销毁某个对象,那么无论析构函数中的代码是什么,您都会看到真正的问题


因此,尽管我同意这样的观点,即它可以隐藏真正的设计缺陷,并且个人不在析构函数中使用FreeAndNil,但发现这种设计缺陷并不是什么灵丹妙药。

这个问题很容易解释,围绕这个问题的争论更主观而非客观。如果对被释放对象的变量引用超出范围,则不需要使用FreeAndNil:

procedure Test;
var
  LObj: TObject;
begin
  LObj := TObject.Create;
  try
    {...Do work...}
  finally
    //The LObj variable is going out of scope here,
    // so don't bother nilling it.  No other code can access LObj.

    //FreeAndNil(LObj);
    LObj.Free;
  end; 
end;
在上面的代码片段中,基于给定的原因,nilling
LObj
变量是没有意义的。但是,如果一个对象变量可以在应用程序的生命周期内被实例化和释放多次,那么就有必要检查该对象是否确实被实例化。检查这一点的简单方法是对象引用是否已设置为
nil
。为了便于将该设置设置为
nil
FreeAndNil()
方法将释放资源,并为您设置
nil
。然后,在代码中,您可以检查对象是否实例化为
LObj=nil
Assigned(LObj)

是否在对象析构函数中使用
.Free
FreeAndNil()
是一个灰色区域,但在大多数情况下,
.Free
应该是安全的,并且不需要在析构函数中对子对象的引用进行零化。关于如何处理构造函数和析构函数中的异常,存在各种各样的争论

现在请注意:如果您更愿意选择使用
.Free
还是
FreeAndNil()
,这取决于上面概述的特定情况,这很好,但是请注意,由于不禁用随后访问的已释放对象引用而导致的错误成本可能非常高。如果随后访问指针(对象已释放,但引用未设置为nil),则可能是您运气不好,并且在访问已释放但未插入的对象引用的多行代码之外发生内存损坏检测。这种bug需要很长时间才能修复,是的,我知道如何使用FastMM


因此,对于包括我在内的一些人来说,当对象指针被释放时,即使不严格需要nilling,简单地将其置零也已成为习惯(可能是一种懒惰的习惯)。

我倾向于相当频繁地使用
FreeAndNil
(无论出于何种原因),但不再使用。使我停止这样做的原因与变量是否需要在之后设置为
nil
无关。它与代码更改有关,特别是变量的类型更改

在将变量类型从
TSomething
更改为接口类型
ISomething
后,我被咬了好几次
FreeAndNil
没有抱怨,并愉快地继续在接口变量上执行它的工作。这有时会导致神秘的撞车事故,无法立即追踪到事故发生的地点,并花了一些时间才找到


所以我又改打免费电话了。当我认为有必要时,我会在事后明确地将变量设置为
nil

我找到了一个stackoverflow问题,谈到
FreeAndNil
FreeAndInvalidate
,提到Microsoft安全开发生命周期现在:

根据上面的SDL建议,以及一些与重用被删除的C++对象的陈旧引用有关的真实错误…

卫生处理值的明显选择为空。然而,这也有缺点:我们知道大量应用程序崩溃是由于空指针取消引用造成的。选择NULL作为一个卫生化值将意味着这个特性引入的新崩溃可能不太可能显露给开发者,因为需要一个适当的解决方案——即正确管理C++对象的生命周期,而不仅仅是一个抑制直接症状的空检查。p> 检查NULL也是一种常见的代码构造,这意味着
procedure FreeAndInvalidate(var obj);
var
   temp : TObject;
const 
   INVALID_ADDRESS = $8123; //address on same page as zero address (nil)
begin
   //Note: Code is public domain. No attribution required.
   temp := TObject(obj);
   Pointer(obj) := Pointer(INVALID_ADDRESS);
   temp.Free;
end;