将Delphi构造函数称为普通方法 - 任何隐藏的副作用?

时间:2016-12-30 12:31:55

标签: delphi constructor

我很困惑:为什么显式地调用Delphi构造函数/作为普通方法不会创建新实例/为什么没有内存泄漏?

以下是一些示例代码:

TMyHelperClass = class(TObject)
private
  fSomeHelperInt: integer;
public
  property SomeHelperInt : integer read fSomeHelperInt write fSomeHelperInt;
  constructor Create (const initSomeHelperInt : integer);
end;

TMyClass = class(TObject)
private
  fHelper : TMyHelperClass;
public
  constructor Create(const initSomeInt: integer);
  destructor Destroy; override;
  property Helper : TMyHelperClass read fHelper;
end;

实现:

constructor TMyHelperClass.Create(const initSomeHelperInt: integer);
begin
  fSomeHelperInt := initSomeHelperInt;
end;

constructor TMyClass.Create(const initSomeInt: integer);
begin
  fHelper := TMyHelperClass.Create(initSomeInt);
end;

destructor TMyClass.Destroy;
begin
  fHelper.Free;
  inherited;
end;

用法:

var
  my : TMyClass;
begin
  my := TMyClass.Create(2016);
  try
    //WHY is this ok to be used ?
    my.Helper.Create(2017);
  finally
    my.Free;
  end;
end;

为什么我可以将TMyHelperClass +的Create构造函数称为普通方法?我的意思是 - 这正是我想要的 - 但是怎么没有问题(有记忆)?

我想答案是因为没有调用Create方法像TMyHelperClass.Create(创建TMyHelperClass的实例)?

这种调用构造函数的方式是否可以使用普通方法/ ok?

1 个答案:

答案 0 :(得分:10)

是的,您可以将构造函数作为普通方法调用 这样做是不好的做法。

  

为什么没有内存泄漏?

来自:http://docwiki.embarcadero.com/RADStudio/Seattle/en/Methods#Constructors

  

使用对象引用(而不是对象引用)调用构造函数时   类引用),它不会创建对象。相反,   构造函数对指定的对象进行操作,仅执行   构造函数的实现中的语句,然后返回一个   引用该对象。通常在一个构造函数上调用   对象引用与继承的保留字一起使用   执行继承的构造函数。

在调用TObject.Create (类引用) vs AObject.Create (实例引用)时,编译器将生成不同的代码。

反模式警告
滥用构造函数作为常规方法将导致分配资源时出现问题 通常构造函数和析构函数是匹配的,但是如果你调用构造函数两次(就像调用实例的构造函数一样),你将分配资源两次,但只释放一次。

如果要将构造函数的主体作为普通方法调用,请创建一个新方法并在构造函数中调用该方法。

E.g:

constructor TTest.Create;
begin
  inherited;
  //Allocate needed resources here.
  Init;
end;

procedure TTest.Init;
begin
  //Do initialization stuff
  //But don't allocate any resources

现在,您可以在需要时安全地调用init方法,而不会发生任何意外事故。

可以在没有“构造”任何东西的情况下调用构造函数的原因是以下代码必须工作:

constructor TTest.Create(const AObject: TObject);
begin                //constructor of TTest happens here
  inherited Create;  //instance call to TParent.Create;
  //Other code
end;

在极少数情况下,您可以完全跳过对构造函数的类调用 以下代码将起作用:

MyTest:= TTest.NewInstance;
//Voodoo code here.
MyTest.Create;

这可用于防止编译器插入在TTest.Create的调用中生成的自动代码。
这很少需要,在20年的编码中,我只使用过一次 这个用例是速度敏感代码,我想避免异常检查的开销和归零分配的空间,这是在Delphi支持带方法的记录之前。

如果我必须再次执行该代码,我将使用一条记录,并在堆上分配一个包含1000条记录的池,并根据需要将其移出。

相关问题