对已释放的对象的错误引用

时间:2008-09-22 06:49:25

标签: delphi

有没有办法确定我们对某个对象持有一个可用的引用,即确定它尚未被释放而留下该非零引用悬空。

7 个答案:

答案 0 :(得分:6)

如果您使用FastMM4作为内存管理器,则可以检查该类是否不是 TFreeObject
或者,在更标准的情况下,使用一个例程,通过检查类VMT 来验证您的对象是否正如它所说的那样。

有这样的ValidateObj函数已经存在了一段时间(由Ray Lischner和Hallvard Vassbotn撰写:http://hallvards.blogspot.com/2004/06/hack-6checking-for-valid-object.html

这是另一个:

function ValidateObj(Obj: TObject): Pointer;
// see { Virtual method table entries } in System.pas
begin
  Result := Obj;
  if Assigned(Result) then
    try
      if Pointer(PPointer(Obj)^) <> Pointer(Pointer(Cardinal(PPointer(Obj)^) + Cardinal(vmtSelfPtr))^) then
        // object not valid anymore
        Result := nil;
    except
      Result := nil;
    end;
end;

更新:有点谨慎......上面的函数将确保结果是nil或有效的非nil对象。如果内存管理器已经重新分配了以前释放的内存,它并不能保证Obj仍然是你认为的那样。

答案 1 :(得分:3)

没有。除非您使用引用计数或垃圾收集器之类的东西,以确保在零引用之前不会释放任何对象。

如果您使用接口,Delphi可以为您做引用计数。当然Delphi for .Net有一个行李收集器。

如前所述,您可以使用Delphi的知识或内存管理器内部来检查有效的指针或对象,但它们并不是唯一可以指向您的指针。因此,即使使用这些方法,也无法覆盖所有指针。并且你的指针也有可能再次有效,但是给了其他人。所以它不是你要找的指针。你的设计不应该依赖它们。使用工具检测您所做的任何参考错误。

答案 2 :(得分:1)

标准,不......

这就是为什么VCL组件可以注册自己以通知对象的销毁,以便他们可以从内部组件列表中删除引用,或者只是重置其属性。

因此,如果您想确保没有任何无效的引用,则有两种选择:

  • 实现每个类都可以订阅的销毁通知处理程序。
  • 修改代码的方式是引用不会通过不同的对象传播。例如,您可以仅通过另一个对象的属性提供对引用的访问。而不是将引用复制到私有字段,而是访问另一个对象的属性。

答案 3 :(得分:1)

正如其他人所说,没有明确的方法,但如果你很好地管理所有权,那么FreeAndNil例程将确保你的变量是零,如果它没有指向任何东西。

答案 4 :(得分:1)

无论如何检查引用是否有效通常不是一个好主意。如果引用无效,则程序将在使用无效引用的位置崩溃。否则,无效引用可能会存活更长时间并且调试变得更难。

以下是一些为什么最好崩溃无效引用的参考。 (他们谈论Win32中的指针,但这些想法仍然相关):

答案 5 :(得分:0)

不幸的是,除了通过精心编写正确的代码之外,没有办法100%保证指向任何东西的指针仍然有效。

答案 6 :(得分:0)

使用接口引用(而不是对象引用)可以避免这些无效指针问题,因为代码中没有显式调用Free。