首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Delphi与单元中的终结化

Delphi与单元中的终结化
EN

Stack Overflow用户
提问于 2010-02-20 14:47:44
回答 6查看 15.1K关注 0票数 4

我有两个单元unitA和unitB。类TFoo在unitB中声明。

在unitA的终结过程中调用B.Free总是安全的吗?

它如何依赖于unitA和unitB在dpr中的顺序?

在执行unitA finalization时,我可以确保unitB存在吗?

代码语言:javascript
复制
unit unitB;
interface
type
 TFoo = class
   // code...
  end;
 // code....
end;

unit unitA;
// code..
implementation
uses
 unitB;
var
 A: TStringList;
 B: UnitB.TFoo;

initialization
 A:= TStringList.Create;
 B:= UnitB.TFoo.Create;
finalization
 A.Free;
 B.Free;  // Is it safe to call?
end.
EN

回答 6

Stack Overflow用户

回答已采纳

发布于 2010-02-20 15:26:08

可以,因为B是在单元A中创建的。规则是根据初始化部分在DPR中的顺序调用它们,除非其中一个单元引用了另一个单元。在这种情况下,首先初始化引用的单元。最终完成的顺序是相反的。

在您的案例中,单元B没有初始化部分,因此它是一个无意义的点。但是,在执行单元A初始化部分时,它将使用单元B中的TFoo定义。

关于初始化和结束部分的另一个警告-它们发生在全局异常处理程序之外。那里发生的任何异常都会终止应用程序。因此,在大型程序中,跟踪和调试这些异常可能是一件痛苦的事情。你可以考虑在那里使用你自己的异常日志,只是为了确保。

票数 16
EN

Stack Overflow用户

发布于 2010-02-20 18:42:27

no。你可以尝试,你可以希望,但不能保证在调用初始化和结束的顺序。参见qc72245qc56034many more

更新:

  1. finalization部分的执行顺序与初始化相反。您的示例是安全的,您不依赖于单元之间的调用初始化部分
  2. Delphi可以混合调用单元(点1仍然有效,初始化和结束部分都交换)

示例:

代码语言:javascript
复制
unitA // no dependency on unitB
var SomeController;
initialization
  SomeController := TSomeController.Create;
finalization
  SomeController.Free;

unitB
uses
  unitA;
initialization
  SomeController.AddComponent(UnitBClass);
finalization
  SomeController.RemoveComponent(UnitBClass);

常用(正确)调用顺序(99.99%):

  1. unitA.initialization
  2. unitB.initialization
  3. run...
  4. unitB.finalization
  5. unitA.finalization

但有时Delphi会编译错误的文件:

  1. unitB.initialization - AV here
  2. unitA.initialization
  3. run...
  4. unitA.finalization
  5. unitB.finalization -还有这里也是

离题的小故事:

我们有一个相当大的项目,Type1在Unit1中,Type2 = class(Type1)在Unit2中。文件按project.dpr排序,几年后添加Unit200 (与Unit1/2无关) Delphi在Unit2开始编译项目,在Unit1初始化之前初始化。唯一安全的解决方案是从初始化节调用您自己的Init函数。

票数 4
EN

Stack Overflow用户

发布于 2010-02-20 15:12:43

据我所知,你所得到的应该是完全有效的。有点笨拙,但很有道理。

但更好的方法可能是在单元B中声明一个变量,并让B初始化/终止它。由于初始化发生在调用任何其他代码之前,因此只要在单元A的uses子句中声明它,它就会在单元A可用之前被初始化。

您可能想要考虑的另一个步骤是进一步将B的单位变量作为按需加载的函数调用,但这也可能取决于您的用法。

例如

代码语言:javascript
复制
unit unitB;
interface
type
 TFoo = class
   // code...
  end;
 // code....
 function UnitVarB:TFoo;

implementation

var
  gUnitVarB : TFoo;  

function UnitVarB:TFoo 
begin
  if not assigned(gUnitVarB) then
    gUnitVarB := TFoo.Create;

  result := gUnitVarB;
end;

finalization
  if assigned(gUnitVarB) then
    gUnitVarB.free;  //or FreeAndNil(gUnitVarB);

end;

unit unitA;

// code..
implementation

uses
 unitB;

var
 A: TStringList;

//code...
  ...UnitVarB....
//code...

initialization
 A:= TStringList.Create;
finalization
 A.Free;
end.

我似乎记得单元初始化可能是昂贵的,因为在编译期间,如果您不再直接引用的单元仍然在uses子句中,则智能链接器不会因为初始化部分而删除它。虽然这听起来可能不是那么糟糕,如果每个单元都有一个初始化部分,那么大多数Delphi程序将比它们已经大得多。

我并不是说不要使用它们,但我的经验法则是谨慎使用它们。

您的初始代码示例违反了这一规则。我想我应该提一下。

瑞安

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/2301355

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档