为什么我要在析构函数中使用Free而不是FreeAndNil?

Rol*_*son 11 delphi destructor delphi-2007

我已经阅读了针对FreeAndNil的案例,但仍然不明白为什么我不能在类析构函数中使用此方法?谁能解释一下.

更新:我认为Eric Grange的评论对我来说最有用.链接表明,如何处理它并不明显,这主要是品味问题.FreeAndInvalidate方法也很有用.

Lar*_*ens 14

The problem with that is that many seem to use FreeAndNil as some magic bullet that will slay that mysterious crash dragon. If using FreeAndNil() in the destructor seems to solve a crash or other memory corruption problems, then you should be digging deeper into the real cause. When I see this, the first question I ask is, why is the instance field being accessed after that instance was destroyed? That typically points to a design problem.

It argues that it hides the real problem you have. It must mean your code is accessing properties/fields/methods of an object that is already destroyed (the destructor is called). So instead of hiding the real problem with FreeAndNil you should really be solving the underlying problem.

This code below would not crash if you would use FreeAndNil PropertyA in the destructor of SomeObject. But it hides the real problem that SomeObject is used after it is destroyed. It is better to solve this design problem (accessing destroyed objects) instead of hiding it.

SomeObject.Free;  // Destructor called
if Assigned(SomeObject.PropertyA) then  // SomeObject is destroyed, but still used
  SomeObject.PropertyA.Method1;  
Run Code Online (Sandbox Code Playgroud)

EDIT

On the other case, one could argue that if FreeAndNil is not used, the code would not crash either. Since even though the object is destroyed, the memory might not be reused and all structures might be in tact. The code above might even run without problems if Free is used to destroy PropertyA instead of FreeAndNil.

And if FreeAndNil was used to destroy SomeObject, you would also see the real problem no matter what the code in the destructor is.

So although I agree with the argument that it could hide the real design flaw and personally do not use FreeAndNil in destructors, it is not some magic bullet to discover such design flaws.

  • 为了保护,您可以使用"FreeAndInvalidate"(http://delphitools.info/2010/02/06/dont-abuse-freeandnil-anymore/)之类的内容使引用无效而不仅仅是nil,以便进一步尝试访问该对象将触发异常. (4认同)

Cal*_*ngh 7

这个问题很容易解释,围绕这个问题的争论比客观更主观.如果对被释放对象的变量引用超出范围,则无需使用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;
Run Code Online (Sandbox Code Playgroud)

在上面的代码片段中,LObj由于给出的原因,nilling 变量将是毫无意义的.但是,如果可以在应用程序的生命周期中实例化并释放多次对象变量,则有必要检查该对象是否确实已实例化.检查这个的简单方法是对象引用是否已设置为nil.为了便于设置nil,该FreeAndNil()方法将释放资源,并nil为您设置.然后,在代码中,您可以检查对象是否使用LObj = nil或实例化Assigned(LObj).

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

现在要注意:如果你喜欢选择是否使用.Free或者FreeAndNil()根据上面列出的具体情况,这很好,但请注意,由于不对随后访问的自由对象引用而导致的bug成本可能非常高.如果随后访问指针(对象已释放但引用未设置为nil),则可能发生您不幸的情况,并且检测到内存损坏会发生许多代码行,而不是访问已释放但未填充的对象引用.这种bug可能需要很长时间才能修复,是的,我知道如何使用FastMM.

因此,对于包括我在内的一些人来说,即使不是非常必要的,也只是在释放所有对象指针时,习惯(可能是懒惰的)习惯.


Hei*_*cht 5

我倾向于FreeAndNil经常使用(无论出于何种原因)但不再使用.让我停止这样做的原因与变量是否需要nil事后无关.它与代码更改有关,尤其是变量的类型更改.

在将变量类型更改为TSomething接口类型后,我被咬了好几次ISomething.FreeAndNil不抱怨,并愉快地继续在接口变量上工作.这有时会导致神秘的崩溃,无法立即追溯到它发生的地方,并花了一些时间才能找到.

所以我转回去打电话Free.当我认为有必要时,我nil明确地将变量设置为.