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

时间:2015-04-24 02:36:13

标签: delphi memory-management memory-leaks

我最近读过很多关于此的内容,但从未找到最终答案 所以,例如,如果我写:

Form1 := TForm1.Create(Application);

应用程序应该负责从存储器中释放表单吗? 为什么人们通常会这样做:

Form1 := TForm1.Create(Application);
Form1.ShowModal;
Form1.Free; 

...
在某些地方看到,如果你试图“释放”已经被释放的对象,你会获得一个EAccessviolation消息,但是在我测试时并不总是如此。

那么请问,这究竟是如何运作的? 这个EAccessviolation让我疯狂,我怎么能完全理解这件事?我在哪里可以找到这些宝贵的信息!??

2 个答案:

答案 0 :(得分:11)

一般规则是:

  • 如果您要自行释放,请使用nil作为所有者。
  • 如果您不打算自行释放,请指定一位负责释放它的所有者。

所以,如果您的代码是这样的:

Form1 := TForm1.Create(...)
Form1.ShowModal;
Form1.Free;

您应该将nil作为所有者编写,并在try..finally块中保护它:

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之外,我总是立即删除该自动生成的变量,并且永远不会自动创建除数据模块之外的任何东西(可以在主窗体之前自动处理没有任何问题,因为数据模块不能是主窗体)。

答案 1 :(得分:2)

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

Application对象在终止时被销毁,因此如果您依赖它来销毁您的表单,那么在终止之前不会发生这种情况。

这里的关键点是指定一个所有者控制销毁所拥有的组件,以及 时销毁它。

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

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

因为你明确地销毁它所以没有给他们一个所有者。并确保Form是一个局部变量。

如果你确实通过了一个拥有者,那么它不会受到特别的伤害。当所有者被告知其责任时,这将是浪费,然后通知它不再负责。

但如果你这样做了:

Form := TMyModalForm.Create(Self);
Form.ShowModal;

然后每次你展示模态形式时,你都会泄漏一个不会被销毁的形式,直到拥有的形式被销毁。如果您使Application拥有,则模态表格将被泄露直至终止。

表格之间的所有权对于主要形式和与主要形式一样长寿的无形亲属来说是合理的。无模式表单可以由主表单拥有,然后在主表单被销毁时自动销毁。

但是如果主表单中包含对无模式表单的引用,那么我可能只是将它无主并且从主表单的析构函数中明确地销毁。

@dummzeuch指出,如果您将Position设置为poOwnerFormCenter,那么框架会要求您提供表单作为所有者。在我看来,这是一个糟糕的设计,它将生命周期管理与视觉布局相结合。但这就是设计,所以你不得不同意它。虽然没有什么可以阻止你明确地销毁一个拥有的组件。你可以这样做:

Form := TMyModalForm.Create(Self); // Self is another form
try
  Form.Position := poOwnerFormCenter;
  Form.ShowModal;
finally
  Form.Free;
end;

当您销毁表单时,会通知其所有者,并且已删除的表单将被删除所有者组件的所有者列表。

主要形式本身很有趣。它必须由Application拥有,因为必须通过调用Application.CreateForm来创建主表单。这是你应该拨打Application.CreateForm的唯一时间。主要表单通常是Application应拥有的唯一表单。特别是如果您采用其他形式无主的政策,或由产生它们的表格所拥有。

但是如果你让主要形式在终止时被销毁,那么当Application被摧毁时,你就会被抓出来。当以这种方式编码时,我在终止时遇到了间歇性的运行时错误。我的补救措施是明确销毁主要表单作为主.dpr文件正文的最终行为。也就是说,在Application.Run返回后销毁主窗体。