Delphi7-何时使用.create(应用程序)以及何时使用.create(nil)?

Delphi7-何时使用.create(应用程序)以及何时使用.create(nil)?,delphi,memory-management,memory-leaks,Delphi,Memory Management,Memory Leaks,最近我读了很多关于这方面的文章,但从未找到最终答案。 例如,如果我写: Form1:=TForm1.Create(应用程序) 应用程序应负责将窗体从内存权限中释放出来? 为什么人们通常会这样做: Form1 := TForm1.Create(Application); Form1.ShowModal; Form1.Free; ?? 在一些地方看到,如果您尝试“释放”一个已经释放的对象,您将得到一个EAccessviolation消息,但正如我测试的,它并不总是正确的 那么,这究竟是如何运作的

最近我读了很多关于这方面的文章,但从未找到最终答案。
例如,如果我写:

Form1:=TForm1.Create(应用程序)

应用程序应负责将窗体从内存权限中释放出来?
为什么人们通常会这样做:

Form1 := TForm1.Create(Application);
Form1.ShowModal;
Form1.Free; 
??
在一些地方看到,如果您尝试“释放”一个已经释放的对象,您将得到一个EAccessviolation消息,但正如我测试的,它并不总是正确的

那么,这究竟是如何运作的呢??
这件事快把我逼疯了,我怎么能完全理解这件事??我在哪里可以找到这些宝贵的信息

一般规则是:

  • 如果您要自己释放它,请使用
    nil
    作为所有者
  • 如果您不打算自己释放它,请指定一位负责释放它的所有者
因此,如果您的代码是这样的:

Form1 := TForm1.Create(...)
Form1.ShowModal;
Form1.Free;
Form := TMyModalForm.Create(nil);
try
  Form.ShowModal;
finally
  Form.Free;
end;
您应该使用
nil
作为所有者编写它,并在try.finally block中保护它:

procedure TForm1.Button1Click(Sender: TObject);
var
  AForm: TForm2;
begin
  AForm := TForm2.Create(nil);
  try
    AForm.ShowModal;
  finally
    AForm.Free;  // You know when it will be free'd, so no owner needed
  end;
end;
另一方面,如果您打算将其保留一段时间,请指定一位所有者,以便稍后将其释放:

procedure TForm1.Button1Click(Sender: TObject);
var
  AForm: TForm2;
begin
  AForm := TForm2.Create(Application);
  // Here you don't know when it will be free'd, so let the
  // Application do so
  AForm.Show;
end;
如果按照我在这里演示的方式执行,这两种技术都不会导致访问冲突。注意,在这两种情况下,我都没有使用IDE生成的
Form2
变量,而是使用了一个本地变量来避免混淆。这些IDE生成的变量是有害的(除了必需的
Form1
或表示主窗体的任何名称,必须由应用程序自动创建和拥有)。除了主窗体的var之外,我总是立即删除自动生成的变量,并且永远不会自动创建任何东西,可能除了datamodule之外(datamodule可以在主窗体之前自动创建,没有任何问题,因为datamodule不能成为主窗体)。

一般规则是:

  • 如果您要自己释放它,请使用
    nil
    作为所有者
  • 如果您不打算自己释放它,请指定一位负责释放它的所有者
因此,如果您的代码是这样的:

Form1 := TForm1.Create(...)
Form1.ShowModal;
Form1.Free;
Form := TMyModalForm.Create(nil);
try
  Form.ShowModal;
finally
  Form.Free;
end;
您应该使用
nil
作为所有者编写它,并在try.finally block中保护它:

procedure TForm1.Button1Click(Sender: TObject);
var
  AForm: TForm2;
begin
  AForm := TForm2.Create(nil);
  try
    AForm.ShowModal;
  finally
    AForm.Free;  // You know when it will be free'd, so no owner needed
  end;
end;
另一方面,如果您打算将其保留一段时间,请指定一位所有者,以便稍后将其释放:

procedure TForm1.Button1Click(Sender: TObject);
var
  AForm: TForm2;
begin
  AForm := TForm2.Create(Application);
  // Here you don't know when it will be free'd, so let the
  // Application do so
  AForm.Show;
end;

如果按照我在这里演示的方式执行,这两种技术都不会导致访问冲突。注意,在这两种情况下,我都没有使用IDE生成的
Form2
变量,而是使用了一个本地变量来避免混淆。这些IDE生成的变量是有害的(除了必需的
Form1
或表示主窗体的任何名称,必须由应用程序自动创建和拥有)。除了主窗体的var之外,我总是立即删除自动生成的变量,并且永远不会自动创建任何东西,可能除了datamodule之外(datamodule可以在主窗体之前自动创建,没有任何问题,因为datamodule不能是主窗体).

组件的
所有者的任务是在销毁所有者时销毁所有拥有的组件

应用程序
对象在终止时被销毁,因此如果您依赖它来销毁表单,则在终止之前不会发生这种情况

这里的关键点是指定所有者既控制销毁所属组件的人员,也控制销毁所属组件的时间

在你的情况下,你有一个模态形式,你想有一个短暂的生命。总是这样写:

Form1 := TForm1.Create(...)
Form1.ShowModal;
Form1.Free;
Form := TMyModalForm.Create(nil);
try
  Form.ShowModal;
finally
  Form.Free;
end;
给他们一个所有者是没有意义的,因为你明确地破坏了它。并确保
Form
是一个局部变量

如果你路过一位主人,那就不会特别疼了。这只是浪费,因为业主被告知其责任,然后又被告知不再负责

但如果你这样做了:

Form := TMyModalForm.Create(Self);
Form.ShowModal;
然后,每次显示模态表单时,都会泄漏一个表单,该表单在所属表单被销毁之前不会被销毁。如果您制作了
应用程序
所拥有的,模态表单将泄漏,直到终止

形式之间的所有权是合理的,比如说,主要形式和一个与主要形式一样长寿的无模式亲属。无模式窗体可以由主窗体拥有,然后在主窗体被销毁时自动销毁

但是,如果主窗体持有对无模式窗体的引用,那么我可能只是让它从主窗体的析构函数中无主并显式销毁

@dummzeuch提出了一个很好的观点,即如果您将
位置设置为
poOwnerFormCenter
,那么框架希望您提供一个表单作为所有者。在我看来,这是一个糟糕的设计,它将生命周期管理与可视化布局混为一谈。但这就是设计,所以你不得不接受它。但是,没有什么可以阻止您显式地销毁一个拥有的组件。您可以这样做:

Form := TMyModalForm.Create(Self); // Self is another form
try
  Form.Position := poOwnerFormCenter;
  Form.ShowModal;
finally
  Form.Free;
end;
销毁表单时,将通知其所有者,并从所有者的自有组件列表中删除已销毁的表单

主要形式本身很有趣。由于必须通过调用
Application.CreateForm
来创建主表单,因此它必须归
Application
所有。这是唯一一次应该调用
Application.CreateForm
。主窗体通常是
应用程序
应该拥有的唯一窗体。特别是如果您采取了让其他窗体不拥有或由生成它们的窗体拥有的策略

但是如果您让主窗体在终止时被销毁,当
应用程序
被销毁时,您可能会被抓获。当以这种方式编码时,我在终止时遇到了间歇性的运行时错误。我的补救办法是明确地销毁主文件