动态创建/发布运行时表单的正确方法是什么?

时间:2011-06-10 18:41:07

标签: delphi free dynamic destroy

我总是尝试创建具有内存使用情况的应用程序,如果你不需要它,那么不要创建它就像我看待它一样。

无论如何,请以下面的例子为例:

Form2:= TForm2.Create(nil);
try
  Form2.ShowModal;
finally
  Form2.FreeOnRelease;
end;

我实际上认为Form2.Destroy可能是更好的选择,这让我想到了我的问题..

致电:

之间有什么区别?
Form2.Destroy;
Form2.Free;
Form2.FreeOnRelease;

他们都做同样或类似的工作,除非我遗漏了什么。

还应该何时使用上述任何一种?显然,在释放对象时,我理解这一点,但在某些情况下,DestroyFree更适合吗?

5 个答案:

答案 0 :(得分:14)

  

Form2:= TForm2.Create(nil);

这是一种代码味道,因为Form2可能是IDE生成的全局变量,通常包含IDE创建的TForm2。您最有可能想要使用局部变量,并使用更好的名称。这不是一个错误,只是一个代码味道。

  

Form2.Destroy与Form2.Free

使用Form2.Free,因为它无论如何都会调用Destroy。你可以 CTRL + 点击名称(Free)上的来查看它的实现。如果Free不是零,则基本上Destroy会调用Self

  

Form2.FreeOnRelease

正如documentation所说,"It should not be necessary to call FreeOnRelease directly."

答案 1 :(得分:9)

我以前从未真正听说过FreeOnRelease。快速的谷歌搜索出现了原因。 From the official documentation:

  

当一个人调用FreeOnRelease时   由组件实现的接口   被释放。使用FreeOnRelease   在内部并调用相应的   界面方法。它不应该   调用FreeOnRelease所必需的   直接

至于FreeDestroyFree是一项安全功能。它基本上实现为if self <> nil then self.Destroy;,它的创建是为了使构造函数和析构函数安全使用。这是基本的想法:

如果您正在构造一个对象并且引发了一个未处理的异常,则会调用析构函数。如果您的对象包含其他对象,那么在错误发生之前它们可能已经创建或者尚未创建,因此您不能只尝试在所有对象上调用Destroy。但是你需要一种方法来确保已经创建的那些被破坏。

由于Delphi在调用构造函数之前将对象的地址空间清零,因此此时尚未创建的任何内容都保证为 nil 。所以你可以一次又一次地对所有子对象说if FSubObject <> nil then FSubObject.Destroy(如果你忘记了你将会遇到访问冲突),或者你可以使用Free方法,为了你。 (这是对C ++的巨大改进,在调用构造函数之前,内存空间归零,这要求您将所有子对象包装在智能指针中并使用RAII来维护异常安全! )

它在其他地方也很有用,并且没有理由不使用它。我从来没有注意到Free强加了任何可衡量的性能损失,并且它提高了代码的安全性,因此在所有情况下使用它都是个好主意。

话虽如此,在专门处理表单时,还有一个额外的变量来计算公式:Windows消息队列。您不知道是否还有待释放的表单的待处理消息,因此在表单上调用Free并不总是安全的。为此,有Release方法。它会向队列发送一条消息,导致表单在没有更多消息需要处理时自行释放,因此通常是释放不再需要的表单的最佳方式。

答案 2 :(得分:6)

规范形式是:

Form := TMyForm.Create(nil);
try
  Form.ShowModal;
finally
  Form.Free;
end;

永远不要致电Destroy,而是始终致电Free

FreeOnRelease是一只红鲱鱼。有时,如果有排队的邮件发往您的表单或其子级,那么您可能会选择调用Release,尽管这通常表明存在设计问题。

答案 3 :(得分:4)

习惯用法是

procedure SomeProc;
var
  frm: TForm2;
begin
  frm := TForm2.Create(nil);
  try
    frm.ShowModal;
  finally
    frm.Free;
  end;
end;

或者,除非你讨厌with构造,

with TForm2.Create(nil) do
  try
    ShowModal;
  finally
    Free;
  end;

根据the documentation,您永远不应该致电Destroy。事实上,Free完全等同于if Self <> nil then Destroy;。也就是说,它是Destroy的“安全”版本。如果指针恰好是nil,它不会完全崩溃。 [要对此进行测试,请在表单类中添加私有字段FBitmap: TBitmap,然后在OnCreate中添加(例如),尝试FBitmap.FreeFBitmap.Destroy。[]

如果您使用上述方法创建表单,Free非常安全,除非您在表单类中执行一些奇怪的操作。

但是,如果使用CreateForm(TForm2, Form2)创建表单并将表单对象存储在全局实例变量Form2中,并且不立即释放它[例如,如果您希望窗口为你可以使用Release代替Free,以非模态方式在主窗体旁边停留几分钟]。来自the documentation

  

发布不会破坏表单   直到表格的所有事件处理程序   和组件的事件处理程序   表格已完成执行。   发布也保证了所有   表单事件队列中的消息是   在表单发布之前处理。   表单或其表单的任何事件处理程序   孩子们应该使用Release而不是   免费(Delphi)或删除(C ++)。失败   这样做会导致内存访问   错误。

FreeOnRelease对表单没有任何特别的处理。来自文档:

  

没有必要打电话   FreeOnRelease直接发布。

答案 4 :(得分:0)

另一种方式是将caFree传递给formonclose的Action

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Action := caFree;
end