【问题标题】:Delphi manage free memoryDelphi 管理空闲内存
【发布时间】:2016-12-24 18:30:54
【问题描述】:

情况

我正在从 Marco Cantu 的书中学习 Delphi,并且我已经有了 OOP 的经验,因为我通常使用 Java 和 PHP。为了更好地理解我正在阅读的内容,我做了这个测试:

type
 TFraction = class
  private
   number: double;
   num, den: integer;
   fraction: string;
   function hcf(x: integer; y: integer): integer;
  public
   constructor Create(numerator: integer; denominator: integer); overload;
   constructor Create(value: string); overload;
   function getFraction: string;
 end;

这是一个超级简单的类,可以将十进制数转换为分数。我不包括定义构造函数和函数的代码的其他部分,因为它们对我的问题没有用。我正在以这种方式创建对象。

var a: TFraction;
begin

 a := TFraction.Create(225, 35);
 ShowMessage(a.getFraction);
 //The output of ^ is 45/7
 a.Free;

end;

问题

据我所知,我知道一旦我使用了该对象就必须摆脱它,事实上我正在使用Free。通过这种方式,我释放了内存并避免了内存泄漏。

顺便说一句,我还可以覆盖destructor。我不太了解FreeDestroy 的行为。当我必须摆脱不再需要的对象时,我会使用Free。当我覆盖析构函数时,我可以释放对象并进行其他操作吗?

简而言之,什么时候使用 Free 比较好?我什么时候应该更喜欢毁灭?

【问题讨论】:

  • 对不起,Alberto 关于答案 cmets 中正在进行的战争。这是一场持续了数十年的古老战争。但这是您进一步了解当前主题的绝佳机会。
  • 别担心,一切都对学习有用:)

标签: delphi


【解决方案1】:

一般来说,如果您需要在对象销毁期间执行某些操作,否则将使用析构函数,否则不会自动完成。就像释放您在构造函数中初始化的内存一样。在您的示例中,无需覆盖析构函数,因为(大概)您不会创建任何需要手动销毁的东西。

另外,请记住,Destroy 根本不打算由您调用 - 无论是内部还是外部。 Free 会自动为您调用 - 需要做一些额外的工作。 Free 检查对象是否为nil,如果不是nil,则仅调用Destroy

以此为例:

type
  TMyObject = class(TObject)
  private
    FSomeOtherObject: TSomeOtherObject;
  public
    constructor Create;
    destructor Destroy; override;
  end;

constructor TMyObject.Create;
begin
  inherited;
  FSomeOtherObject:= TSomeOtherObject.Create;
end;

destructor TMyObject.Destroy;
begin
  FSomeOtherObject.Free;
  inherited;
end;

作为补充说明,我在上面看到的用法缺少一些东西。如果CreateFree 之间的代码引发了一些异常怎么办?该过程将退出,并且永远不会被释放。因此,您应该使用 try / finally 块...

a := TFraction.Create(225, 35);
try 
  ShowMessage(a.getFraction);
finally
  a.Free;
end;

这将确保无论tryfinally 之间发生什么,finallyend 之间的代码将始终被调用。

【讨论】:

  • “Destroy 不打算被调用”这是不正确的。
  • @FreeConsulting 您能否详细说明这一说法,并考虑回复 Ken 对 Remy 的回答的评论?你能叫它吗?是的。有没有理由直接调用它?不是我所知道的。还是你只是像其他人一样寻找理由来证明我说错了什么?
  • 非常感谢。我已阅读有关内存管理的书的下一章,并且找到了您告诉我的内容。我将使用 Free ,因为他“决定”何时调用析构函数。谢谢:)
  • @FreeConsulting:它不应该被直接调用,除了来自继承的析构函数。那是100%正确的。始终使用Free,不要直接调用Destroy,即使在某些情况下,您确定对象不是nil,因为这意味着您必须做出决定,情况可能会发生变化。如果你总是打电话给Free,你就不必做决定,也不会错。
  • @Rudy 是的,即便如此,只需要一个简单的inherited; 就足够了。它只是简单地遵循继承类的要求。
【解决方案2】:

顺便说一句,我还可以覆盖destructor。我不太了解FreeDestroy 的行为。

Free() 在对象指针不为 nil 时调用析构函数。

Destroy() 是实际的析构函数。

当我必须摆脱不再需要的对象时,我会使用Free。当我覆盖析构函数时,我可以释放对象并进行其他操作吗?

是的。当对象处于被销毁的过程中时,会调用析构函数。重写析构函数是执行与被销毁对象相关的清理操作的好地方。

简而言之,什么时候使用 Free 比较好?我什么时候应该更喜欢毁灭?

可以直接调用Destroy(),但一般首选调用Free(),让它为您调用Destroy()

【讨论】:

  • 您能否提供一个具体示例,说明何时需要调用 Destroy 而不是 Free?我不记得曾经遇到过一个人,并养成了永远不要自己调用 Destroy 的习惯;我有兴趣看到我缺少的这种做法的例外情况。
  • 如果您确定知道给定的对象指针从不为nil(例如包装在try/finally中的局部变量),您可以直接致电Destroy()。如有疑问,请致电Free()。在 RTL/VCL 源代码中,有一些直接调用 Destroy() 的示例(请注意,并不多)。例如,在TComponent.DestroyComponents()
  • Free() 被引入特别是因为构造函数异常的可能性,因为析构函数被自动调用。在进入构造函数之前对象内存被清零,以确保任何未初始化的成员在析构函数中都为零/nil。这样,析构函数编写者就不必跟踪在异常之前初始化了哪些成员。我并不是说不要使用Free()。我们大多数人(包括我自己)都这样做。我只是说Destroy()可以在你知道这样做是安全的并且你不需要检查nil时直接调用。
  • Allen Bauer 早在 2006 年就写过关于这个主题的博客:Exceptional Safety
  • 我认为这里的争论源于 couldshould 之间的区别。我可以决定将伏特加倒入我汽车的油箱中。但是应该我吗?我认为不会,只是为了安全。
猜你喜欢
  • 1970-01-01
  • 2018-08-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-18
  • 2011-07-13
  • 2015-08-17
相关资源
最近更新 更多