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

17 delphi free dynamic destroy

我总是尝试用内存使用来创建我的应用程序,如果你不需要它,那么不要创建它是我看待它的方式.

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

Form2:= TForm2.Create(nil);
try
  Form2.ShowModal;
finally
  Form2.FreeOnRelease;
end;
Run Code Online (Sandbox Code Playgroud)

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

打电话有什么区别:

Form2.Destroy;
Form2.Free;
Form2.FreeOnRelease;
Run Code Online (Sandbox Code Playgroud)

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

还应该何时使用上述任何一种?显然,当释放一个对象时,我理解这一点,但在某些情况下比例如Destroy更适合Free

Cos*_*und 15

Form2:= TForm2.Create(nil);

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

Form2.Destroy与Form2.Free

使用Form2.Free,因为Destroy无论如何它都会调用.您可以CTRL+ Click上的名字(Free),看看它的实现.基本上Free调用Destroyif Self不是nil.

Form2.FreeOnRelease

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

  • @Craig:关键不在于`Form2`是一个非描述性的名称.问题是你不应该在`Unit2`的接口部分使用***global***`var Form2:TForm2`变量,如果你做`try ShowModal finally Free`的话.相反,在这种情况下,您应该使用*local*变量.如果您愿意,可以将其命名为"Form2". (2认同)

Mas*_*ler 10

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

释放组件实现的接口时,将调用FreeOnRelease.FreeOnRelease在内部使用并调用相应的接口方法.没有必要直接调用FreeOnRelease.

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

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

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

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

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


Dav*_*nan 6

规范形式是:

Form := TMyForm.Create(nil);
try
  Form.ShowModal;
finally
  Form.Free;
end;
Run Code Online (Sandbox Code Playgroud)

永远不要打电话Destroy,总是打电话Free.

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

  • 有许多可以想象的情况下,释放是完全合理的,最值得注意的是从内部摧毁一个表格.但研究释放的任何需求肯定是明智的. (2认同)

And*_*and 5

惯用的用法是

procedure SomeProc;
var
  frm: TForm2;
begin
  frm := TForm2.Create(nil);
  try
    frm.ShowModal;
  finally
    frm.Free;
  end;
end;
Run Code Online (Sandbox Code Playgroud)

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

with TForm2.Create(nil) do
  try
    ShowModal;
  finally
    Free;
  end;
Run Code Online (Sandbox Code Playgroud)

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 而不是 Free (Delphi) 或 delete (C++)。否则可能会导致内存访问错误。

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

不需要直接调用 FreeOnRelease。