【问题标题】:Why form destroy event is called more than once?为什么表单销毁事件被多次调用?
【发布时间】:2012-04-12 15:25:04
【问题描述】:

我以前从未在我的程序中注意到它,但是对于我的一个 TForm,我有一个销毁事件,它释放一个对象,被多次调用或触发。我不明白为什么。

procedure THTrendFrm.FormDestroy(Sender: TObject);
begin
  LogAlarm.Free;  <---Invalid Pointer Operation exception is raised
end;

提前致谢,

更新:这是我的程序关闭后的 FastMM 消息窗口。 TAlarmMsg 是从中创建 LogAlarm 的类。

【问题讨论】:

  • 你试过我的建议了吗?在 Application.Run 之后,从您的 .dpr 文件中对表单对象调用 Free。
  • @DavidHeffernan 我确实采纳了你的建议,但 FastMM 仍然发现了错误。
  • 我刚刚发现了我的问题。我刚刚在项目 dpr 文件中看到 Application.CreateForm(THTrendFrm, HTrend) 两次。我删除了副本,它工作正常。

标签: delphi delphi-xe


【解决方案1】:

TForm.OnDestroy 事件不会被多次调用,因此在触发OnDestroy 事件之前,您必须在代码中的其他位置释放LogAlarm 对象。

【讨论】:

  • 我认为有一个 VCL 错误意味着表单可以被销毁两次。我通过销毁 .dpr 文件中的主表单而不是让应用程序通过所有者机制销毁它来解决它
  • Remy,我确实在这一行放了 break 并在我关闭程序时逐步执行。它确实在那条线上中断了两次。第一次,没有异常或错误消息。第二次,它引发了异常。 LogAlarm 对象在同一个 Unit 或 pas 文件中创建和销毁。它在我的项目文件中没有被释放。
  • @DavidHeffernan:我以前从未遇到过这样的错误。
  • @digitalanalog:如果您的断点是两次,那么每次都查看调用堆栈并跟踪表单是如何被破坏两次的。它绝对不应该在正常情况下。
  • 这是我的 QC 报告:qc.embarcadero.com/wc/qcmain.aspx?d=88776 不确定是否是同一件事,但听起来很合理
【解决方案2】:

感谢大卫赫弗南和其他人。我发现了我的问题并修复了它。有问题的 TForm 像这样在我的项目文件中创建了两次。

Application.CreateForm(HTrendFrm, HTrend);

这就解释了为什么 destroy 被调用了两次。

一旦我删除了重复的行,它就可以正常关闭了。

【讨论】:

    【解决方案3】:

    这取决于您如何创建 LogAlarm。

    如果 LogAlarm 是 TComponent 的后代,并且您已使用表单作为所有者创建它,则不应对其调用 Free,因为一旦表单被销毁,该组件将自动清理。

    或者如果你坚持自己清理它,在创建过程中将 owner 设为 nil。

    【讨论】:

    • 释放一个拥有的对象是完全安全的。你最后一句话不正确。释放对象会将其从其所有者的拥有对象列表中删除。
    • 我不是这个意思。我的观点是,如果您不希望所有者进行清洁,则应该像 create(nil) 一样构建。在调试时,最好先排除编程错误,然后再假设它是 vcl 中的错误。
    • 我稍微改写了最后一句话
    • 盲目地调用 free 一个拥有的对象并不完全安全,因为你不知道所有者是否同时销毁了它。在这种情况下调用 freeandnil() 可能是一个更好的主意,但我们不要再开始那个主题了 :)
    • 这个 Q 的问题是表单被销毁了两次。访问 LogAlarm 时会引发错误,但这只是第二次销毁中的第一次访问。 LogAlarm 的所有权既不存在也不存在。表单不应被销毁两次。
    猜你喜欢
    • 2012-02-20
    • 2012-09-10
    • 1970-01-01
    • 2012-01-30
    • 1970-01-01
    • 2019-12-04
    • 1970-01-01
    • 2023-03-31
    • 1970-01-01
    相关资源
    最近更新 更多