18

我总是尝试在考虑内存使用的情况下创建我的应用程序,如果您不需要它,那么不要创建它,这是我看待它的方式。

无论如何,以以下为例:

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

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

调用有什么区别:

Form2.Destroy;
Form2.Free;
Form2.FreeOnRelease;

他们都做相同或相似的工作,除非我错过了什么。

还有什么时候应该使用上述任何一种?显然,在释放对象时我明白这一点,但在某些情况下比例如Destroy更适合Free

4

5 回答 5

16

Form2:= TForm2.Create(nil);

这是代码异味,因为Form2可能是全局的 IDE 生成变量,通常会保存 IDE-created TForm2。您很可能想要使用一个局部变量,并且使用一个更好的名称。这不一定是错误,只是代码气味。

Form2.Destroy 与 Form2.Free

使用Form2.Free, 因为它Destroy无论如何都会调用。您可以在名称 ( ) 上CTRL+以查看它的实现。本质上调用if不是 nil。ClickFreeFreeDestroySelf

Form2.FreeOnRelease

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

于 2011-06-10T18:55:21.843 回答
10

我以前从未真正听说FreeOnRelease过。一个快速的谷歌搜索出现了原因。 来自官方文档:

FreeOnRelease 在组件实现的接口被释放时调用。FreeOnRelease 内部使用,调用对应的接口方法。不需要直接调用 FreeOnRelease。

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

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

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

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

话虽如此,在具体处理表单时,还有一个额外的变量需要考虑:Windows 消息队列。您不知道要释放的表单是否仍有待处理的消息,因此调用Free表单并不总是安全的。为此,有Release方法。它将一条消息发布到队列中,导致表单在没有更多消息要处理时自行释放,因此它通常是释放不再需要的表单的最佳方式。

于 2011-06-10T18:51:52.583 回答
6

规范形式是:

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

从不打电话Destroy,总是打电话Free

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

于 2011-06-10T19:09:39.743 回答
5

惯用用法是

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;

Destroy根据文档,您永远不应该打电话。实际上,Free正好等价于if Self <> nil then Destroy;。也就是说,它是Destroy. 如果指针恰好是,它不会完全崩溃nil。[要对此进行测试,请在您的表单类中添加一个私有字段FBitmap: TBitmap,然后在 OnCreate(例如),尝试FBitmap.Freevs. FBitmap.Destroy]

如果您使用上述方法创建表单,Free则非常安全,除非您在表单类中做了一些奇怪的事情。

但是,如果您使用CreateForm(TForm2, Form2)创建表单并将表单对象存储在全局实例变量中Form2并且您不立即释放它[例如,如果您希望窗口以非模态方式停留在主表单旁边几分钟],您可能应该使用Release而不是Free. 从文档中,

Release 不会销毁表单,直到表单的所有事件处理程序和表单上组件的事件处理程序执行完毕。Release 还保证表单的事件队列中的所有消息都在表单被释放之前得到处理。表单或其子项的任何事件处理程序都应使用 Release 而不是 Free (Delphi) 或 delete (C++)。否则会导致内存访问错误。

FreeOnRelease与表格没有什么特别的关系。从文档:

不需要直接调用 FreeOnRelease。

于 2011-06-10T18:52:17.653 回答
0

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

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Action := caFree;
end
于 2018-02-13T10:26:11.733 回答