Delphi-为什么TObject.InitInstance是公共的?

Delphi-为什么TObject.InitInstance是公共的?,delphi,Delphi,我对德尔福有些陌生,这个问题正是我好奇的地方。(我也只是偶然尝试使用它,结果发现我不应该这么做。) 如果您查看文档,它会告诉您不要使用它,除非您正在重写NewInstance。该方法也是公开的。如果用户永远不应该调用它,为什么不让它受到保护呢?它为开发人员提供了一种不使用NewInstance(堆栈/内存池中的内存)创建对象的方法。当然,千万不要说永不。在VCL中,太多的东西是私有的,而不是虚拟的,所以我有点喜欢这些东西是公共的 对于正常使用来说,它并不是必需的,但在特定情况下,您可以使用它来批

我对德尔福有些陌生,这个问题正是我好奇的地方。(我也只是偶然尝试使用它,结果发现我不应该这么做。)


如果您查看文档,它会告诉您不要使用它,除非您正在重写
NewInstance
。该方法也是公开的。如果用户永远不应该调用它,为什么不让它受到保护呢?

它为开发人员提供了一种不使用NewInstance(堆栈/内存池中的内存)创建对象的方法。

当然,千万不要说永不。在VCL中,太多的东西是私有的,而不是虚拟的,所以我有点喜欢这些东西是公共的

对于正常使用来说,它并不是必需的,但在特定情况下,您可以使用它来批量分配对象。NewInstance为对象保留一点内存,然后调用InitInstance对其进行初始化。您可以编写一段代码,一次性为大量对象分配内存,然后为该大块的不同部分调用InitInstance来初始化其中的不同块。这样的实施可以成为实施的基础

通常你根本不需要这样的东西,但是如果你真的想/需要的话,你可以这样做是很好的

它是如何工作的

有趣的是:Delphi中的构造函数只是一种方法。Create方法本身没有做任何特殊的事情。如果你看它,它只是一个方法,就像其他方法一样。TObject里甚至都是空的

您甚至可以在实例上调用它(调用MyObject.Create而不是TMyObject.Create),它根本不会返回新对象。该键位于
构造函数
关键字中。这告诉编译器,在执行TAnyClass.Create方法之前,它还应该构造一个实际的对象实例

这种构造基本上意味着调用
NewInstance
NewInstance
为对象的数据分配一段内存。之后,它调用
InitInstance
对该内存进行一些特殊的初始化,首先清除它(用零填充)

分配内存是一项相对昂贵的任务。内存管理器(编译到应用程序中)需要找到一块空闲内存并将其分配给对象。如果它没有足够的可用内存,它需要向Windows请求提供更多内存。如果要创建数千个甚至数百万个对象,那么这可能是低效的

在这些罕见的情况下,您可以决定一次性为所有这些对象分配内存。在这种情况下,您根本不会调用构造函数,因为您不想调用NewInstance(因为它会分配额外的内存)。相反,您可以自己调用InitInstance来初始化大块内存


不管怎样,这只是一个原因的假设。也许根本没有理由。我在VCL中看到了太多不合理的应用可见性级别。也许他们根本就没想过

自从1992年年中德尔福事件开始时我就在身边,这个问题可能有几个答案。如果您查看Delphi 1中TObject的原始声明,TObject上没有任何受保护/私有成员。这是因为在Delphi开发的早期,随着语言中异常的引入,异常是从不同于其他对象的堆中分配的。这就是NewInstance/InitInstance/CleanupInstance/FreeInstance函数的起源。在类类型上重写这些函数,您可以控制对象的分配位置

近年来,我使用这个功能创建了一个对象实例的缓存,这些对象实例实际上是“可回收的”。通过截取NewInstance和FreeInstance,我创建了一个系统,在这个系统中,实例在取消分配时不会返回到堆中,而是放在一个无锁/低锁链接列表中。这样可以更快地分配/释放特定类型的实例,并消除内存管理器中的大量偏移

通过使InitInstance为public(与CleanupInstance相反),这将允许从其他实用程序函数调用这些方法。在我提到的上述情况中,可以在现有内存块上调用InitInstance,而不必仅从NewInstance调用。假设NewInstance调用一个通用函数来管理前面提到的缓存。类实例的“作用域”丢失,因此调用InitInstance的唯一方法是将它的“作用域”公开

总有一天,我们可能会发布实现上述功能的代码。。。目前,它是一个内部“研究”项目的一部分


哦,作为一个旁白,也是一个历史课。。。在Delphi1发行版之前,异常实例如何分配/释放的设计返回到使用与所有其他对象相同的堆。由于一个总体的集体失误,我们假设需要分配所有异常对象实例来“保护”内存不足的情况。我们推断,如果因为内存管理器“内存不足”而尝试引发异常,我们将如何分配异常实例!?我们已经知道在那一点上没有记忆了!所以我们决定对所有异常都需要一个单独的堆。。。直到查克·贾兹泽夫斯基或安德斯·海尔斯伯格(我完全忘了是哪一个)想出了一个简单、相当聪明的解决方案。。。只需在启动时预先分配内存不足异常!我们仍然需要控制是否应该实际释放异常(异常实例一旦处理就会自动释放),因此整个NewInstance/FreeInstance机制仍然存在。

可能是历史事故。很可能只有原著作者才能告诉你确切的答案。我可能是天真地认为可能有一个真正的原因。肯定有一个原因。只是这很小