Delphi中抽象错误的可能模糊原因是什么?

8
在 Delphi 7 项目中,我们安装了 FastMM。不久之后,我们注意到其中一个窗体在关闭时开始发出“抽象错误”消息。我已经进行了大量调试,但到目前为止还找不到原因。通常出现此错误消息的原因似乎不适用于此处。应用程序没有定义抽象类。我还在窗体中搜索可能使用 TStrings 或类似内容的地方。最重要的是,我们没有对该窗体进行任何更改(好吧,我们认为没有)。它只是坏掉了。
这个错误除了尝试调用未实现的方法之外,还有其他可能的原因吗?
FastMM 是否可能启用了应用程序中的一些晦涩 bug,并一直隐藏到现在?
如果这些问题的答案是否定的,那么我将继续寻找未实现的方法调用,同时松了一口气,因为我没有错过其他东西。

1
我曾经在创建窗体时遇到过“抽象错误”,通常发生在你创建一个窗体(Form1),添加组件等,然后创建另一个继承Form1的窗体(Form2),保存一切,到目前为止都很好。现在,如果你修改Form1(添加组件,修改组件属性...),保存并重新构建,当创建Form2时 -> 报错“抽象错误”。从那以后,我一直避免在设计中使用窗体继承。 - user497849
5个回答

12

如果存在内存损坏,则可能会引发各种错误,并且很难找到原因。

回答您的问题:1)是的,抽象错误也可能是由内存损坏引起的;2)是的,启用FastMM可以使通常不被注意但仍应该修复的错误可见。

查找内存错误的一些通用建议:

  1. 尝试在FastMM中设置“FullDebugMode”。
  2. 确保您创建的每个内容都与Free成对出现。
  3. 确保没有释放超过一次的内容。
  4. 确保对象在被创建后(或被释放前)不再使用。
  5. 开启提示和警告(并在出现时进行修复)。

3
+1. 我会加上 5. 打开提示和警告(并在出现时修复它们) - Ken White
@KenWhite:绝对没错。我会把那个 1. 打开提示和警告...,重点在于 1. :-) - Marjan Venema
2
@KenWhite 已添加 :-) 唯一的问题是,在旧代码中可能会有数百个警告,修复它们(不正确地)可能会引入新的错误。因此必须小心处理。 - Ville Krumlinde
关于数字2。这将“仅”导致内存泄漏,而不是访问冲突。 - Gabriel
为了解决EscapeVelocity的问题,我会集中精力于第四个方面。 - Gabriel
显示剩余2条评论

3

"它刚刚损坏了" - 可能它一直都是坏的,现在你知道了。

我曾经遇到过在按钮事件中关闭表单时出现问题的情况。表单被销毁后,剩余的按钮消息被分派给一个不存在的按钮。释放方法通过向表单发送wm_close消息来避免这种情况(从记忆中得知)。


你的回答帮了我很多。我有一个按钮,它会删除自己并添加新的按钮。诀窍是在按钮代码退出后设置信号量以重新加载。 - CharlesW

2

回答问题1:“除了尝试调用未实现的方法外,是否还有其他可能导致此错误的原因?”

有。在我的情况下,这是导致抽象错误的原因:

TWinControl(Sender).Visible:= FALSE;        

这个代码片段可以在发送器是TButton时工作,但如果发送器是其他东西(例如TAction),它就会引发错误。显然这是我的错。我应该使用"as"而不是硬类型转换。
关于第二个问题的答案:是的,我也见过这种情况。我们应该非常清楚,这并不意味着FastMM有缺陷。该漏洞是“休眠”的,只有FastMM才能触发它。 实际上,您应该更加依赖于FastMM来找到问题解决方案。将FastMM切换到完整调试模式以获取帮助。它将协助您:
- 确保对象在被释放后(或在创建之前)不再被使用 - 在某些情况下,整个项目都被搞砸了,我得到了抽象错误。什么都用不了,除非删除DPROJ文件。仅比较当前DPROJ文件和回退中的文件即可查看IDE如何搞砸文件。 - 您还必须修复编译器显示的所有警告!编译器认真对待这一点。它不会没有有效的原因而引发警告。修复它,你可能会解决你的问题。 - 在这种特殊情况下,我还将替换所有".Free"为"FreeAndNil()"。

2

如何安装它?您只需将该单元放入项目的 USES 列表中即可。 - Gabriel
1
是的,就这么简单。 - dummzeuch

0

可能是基类中的一个抽象函数/过程未被实现;

尝试这个:

e.g

 type

   TBaseClass = class (TObject)

 public

      procedure DoSomething;  virtual; abstract; //not implemented procedure

 end;


  type

    TInheritedClass = class (TBaseClass)

 public

      procedure DoSomething; override;

   end;

//Implementation

procedure TInheritedClass.DoSomething;

begin

 //your code

end;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接