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

时间:2014-03-20 17:25:38

标签: delphi

我对Delphi有点新鲜,这个问题只是让我好奇。 (我也只是偶然尝试使用它来发现我不应该这样做。)

如果您查看TObject.InitInstance的文档,它会告诉您不要使用它,除非您重写NewInstance。该方法也是公开的。如果用户永远不应该打电话给它,为什么不保护它呢?

3 个答案:

答案 0 :(得分:28)

自从我在整个Delphi的事情在1992年中左右开始时我就在身边,这个问题可能有几个答案。如果你在Delphi 1中查看TObject的原始声明,TObject上没有任何受保护/私有成员。这是因为在Delphi开发的早期阶段,并且在引入语言异常的同时,异常是从不同的堆中分配的,而不是其他对象。这是NewInstance / InitInstance / CleanupInstance / FreeInstance函数的起源。在类类型上覆盖这些函数,您可以逐字地控制在哪里分配对象。

近年来,我使用此功能创建了一个字面上“循环”的对象实例缓存。通过拦截NewInstance和FreeInstance,我创建了一个系统,其中实例在取消分配时不会返回到堆,而是放在无锁/低锁链表上。这使得分配/释放特定类型的实例的速度更快,并消除了大量进入内存管理器的偏移。

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

其中一天,我们可能会发布执行上述描述的代码......现在它是内部“研究”项目的一部分。

哦,作为一个旁边,也是一个历史课...在Delphi 1发布之前,如何分配/释放Exception实例的设计被返回到使用与所有其他对象相同的堆。由于整体的集体失误,我们假设我们需要分配所有Exception对象实例以“保护”内存不足的情况。我们推断如果因为内存管理器“内存不足”而尝试引发异常,那么我们如何分配异常实例!?我们已经知道那时没有记忆了!所以我们决定所有例外都需要一个单独的堆......直到Chuck Jazdzewski或Anders Heijlsberg(我忘了哪一个),想出一个简单,相当聪明的解决方案......只需预分配启动时内存不足异常!我们仍然需要控制是否应该实际释放异常(异常实例在处理后自动释放),因此整个NewInstance / FreeInstance机制仍然存在。

答案 1 :(得分:3)

好吧永远不要说永远。在VCL中,太多的东西是私有的而不是虚拟的,所以我有点像这个东西是公开的。

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

通常你根本不需要这样的东西,但如果你真的想要/需要的话,那就太好了。

它是如何工作的?

有趣的是:Delphi中的构造函数只是一些方法。 Create方法本身并没有做任何特别的事情。如果你看一下,这只是一种方法。它在TObject中甚至是空的!

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

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

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

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

无论如何,这只是一个假设的原因。也许根本就没有理由。我在VCL中看到过如此多的非理性应用可见性级别。也许他们根本就没想过。 ;)

答案 2 :(得分:-1)

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