Delphi 7 - 何时使用 .create(Application) 以及何时使用 .create(nil)?
Delphi 7 - When to use .create(Application) and when to use .create(nil)?
我最近阅读了很多关于此的资料,但从未找到最终答案。
所以,例如,如果我写:
Form1 := TForm1.Create(Application);
应用程序应该负责从内存中释放表单,对吗?
为什么人们通常会这样做:
Form1 := TForm1.Create(Application);
Form1.ShowModal;
Form1.Free;
??
在某些地方看到,如果您尝试 "free" 一个已经释放的对象,您将收到 EAccessviolation 消息,但正如我测试的那样,它并不总是正确的。
那么请问,这实际上是如何工作的?
这个 EAccessviolation 东西快把我逼疯了,我怎么才能完全理解这个东西??我在哪里可以找到这些宝贵的信息!??
一般规则是:
- 如果您要自己释放它,请使用
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 之外,我总是立即删除那个自动生成的变量,并且从不自动创建任何东西,除了可能的数据模块(可以在主窗体之前自动创建,没有任何问题,因为数据模块不能是主窗体).
一个组件的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
returns后的主窗体。
我最近阅读了很多关于此的资料,但从未找到最终答案。
所以,例如,如果我写:
Form1 := TForm1.Create(Application);
应用程序应该负责从内存中释放表单,对吗?
为什么人们通常会这样做:
Form1 := TForm1.Create(Application);
Form1.ShowModal;
Form1.Free;
??
在某些地方看到,如果您尝试 "free" 一个已经释放的对象,您将收到 EAccessviolation 消息,但正如我测试的那样,它并不总是正确的。
那么请问,这实际上是如何工作的?
这个 EAccessviolation 东西快把我逼疯了,我怎么才能完全理解这个东西??我在哪里可以找到这些宝贵的信息!??
一般规则是:
- 如果您要自己释放它,请使用
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 之外,我总是立即删除那个自动生成的变量,并且从不自动创建任何东西,除了可能的数据模块(可以在主窗体之前自动创建,没有任何问题,因为数据模块不能是主窗体).
一个组件的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
returns后的主窗体。