代码之家  ›  专栏  ›  技术社区  ›  Greg Beech

析构函数和终结器之间的区别?

  •  36
  • Greg Beech  · 技术社区  · 15 年前

    请注意:这个问题是关于“析构函数”和“终结器”两个词在术语上的差异及其正确用法。我只是提供了他们在C和C++中使用的例子来说明我为什么要问这个问题。我很清楚它是如何在C和CLR中实现的,但是我在询问术语的正确使用。


    在C世界中,术语“析构函数”和“终结器”似乎可以互换使用,我怀疑这是因为C规范使用“析构函数”一词描述了非确定性清理功能,而clr文档总是使用“终结器”一词,因此在C领域中,它们的含义相同。

    然而,在C++/CLI规范中,两者之间存在区别。它允许确定性和非确定性清理,并将术语“析构函数”用于确定性功能,将“终结器”用于非确定性功能:

    终结器提供非确定性清理。终结器是在垃圾收集期间执行的“最后一次机会”函数,通常在未执行析构函数的对象上执行。

    另外,维基百科对 destructor finalizer 指示析构函数和终结符是独立的概念,并支持C++/CLI规范关于决定论的术语的使用:

    与析构函数不同,终结器不是确定性的。当程序显式释放对象时,将运行析构函数。相反,当内部垃圾收集系统释放对象时,将执行终结器。

    问题:

    • 从计算机科学的角度来看,“析构函数”和“终结器”之间是否有明确定义的区别,或者术语是只能在上下文中定义的?

    • 如果有明确定义的差异,那么为什么C规范会使用“错误”的术语?

    4 回复  |  直到 15 年前
        1
  •  39
  •   Eric Lippert    15 年前

    1)行业或学术界使用的“析构函数”和“终结器”之间是否有明确的区别?

    当然有。区别似乎在于析构函数是确定地调用的清理方法,而终结器在垃圾收集器告诉它们时运行。

    2)在这种情况下,C规范出错了——终结器在C中称为“析构函数”。为什么C规范的作者把它弄错了?

    我不知道,但我能猜到。事实上,我有两个猜测。

    猜测1是1999年5月12日没有一篇维基百科文章清楚地描述了这两个概念之间的细微差别。那是因为没有维基百科。还记得没有维基百科的时候吗?黑暗时代,伙计。错误可能只是一个诚实的错误,相信这两个术语是相同的。

    我只知道这两个术语 1999年5月12日相同,定义上的差异后来才演变,因为很明显,迫切需要和懒惰的清理方法之间存在消除歧义的必要性。

    猜测2是1999年5月12日,语言设计委员会希望开放“析构函数”可以作为某种东西实现的可能性。 其他 而不是定稿器。也就是说,“析构函数”被设计成一个C语言概念,它不一定与.NET“终结器”概念一一对应。在设计一种语言的同时,它所处的框架也在设计中,有时您希望将自己与子系统中最新的设计变更隔离开来。

    语言委员会1999年5月12日的说明部分内容如下:

    我们要用这个词 执行的成员的“析构函数” 当一个实例被回收时。班 不能有析构函数;结构不能。 与C++不同,析构函数不能 显式调用。破坏是 不确定性“你不能可靠地 知道析构函数何时执行, 只是说它在某些地方执行 在所有引用之后指向 对象已释放。这个 继承链中的析构函数 按顺序调用,从大多数 后代到最小后代。那里 不需要(也不可能) 派生类以显式调用 基本析构函数。C语言编译程序 将析构函数编译为 适当的CLR表示。为了 这个版本可能意味着 实例终结器 在元数据中区分。CLR可以 在中提供静态终结器 未来;我们看不到任何障碍 使用静态终结器。

    所以,你现在知道了我对这个问题的一切。如果你想了解更多,下次见到安德斯时再问问他。

        2
  •  6
  •   philsquared    15 年前

    严格地说,C没有析构函数(我相信C规范在这一点上很混乱)。 C的终结器看起来像C++析构函数,但是,正如你所说,是非确定性的。 C具有确定性清理形式 IDisposable::Dispose (但这仍然不是一个析构函数)。

    C++/CLI具有确定性析构函数,它看起来像C++析构函数。在cli级别,这些映射到 IDisposable::Dispose() ( IDisposable 是为您实现的)。 C++/CLI具有非确定性终结器,看起来像析构函数,但使用!前缀而不是^前缀。

    C++/CLI使用C语言用于终结器的析构函数相同的语法可能有点混乱,但它更适合C++,它具有确定性破坏的强大传统。

    不幸的是,这些术语缺乏普遍的定义,这意味着你总是需要澄清你在说什么。我个人总是用这个词 终结器 当谈到C概念和储备时 析构函数 对于明确意味着确定性破坏的上下文。

    [更新] 自从我在这里的原始帖子,埃里克·利珀特已经发布了他的回复(接受的答案),并跟进了 blog post 同样。我很高兴看到我们达成一致意见:-)

        3
  •  4
  •   Steve Cooper    15 年前

    我相信“析构函数”是C代码,“终结器”是编译后的CIL方法。C编译器将析构函数转换为终结器。

    编辑:为了更详细,C语言规范将“析构函数”定义为类上的C实例方法。那么,析构函数是C语法的一部分——析构函数是出现在源代码中的语言对象。

    析构函数是实现销毁类实例所需操作的成员。析构函数不能有参数,不能有可访问性修饰符,并且不能显式调用它们。实例的析构函数在垃圾收集期间自动调用。

    “终结器”是公共语言运行库中使用的术语,例如在对 GC.WaitForPendingFinalizers() 它指的是任何.NET语言,而不仅仅是C。任何.NET引用类型都不能有终结器。对于C类(源代码工件),析构函数编译到CIL方法中,CIL方法是clr类型的终结器。

    或者更简洁地说, 析构函数 是为了 终结器 作为 源代码 是为了 机器代码 ;)

        4
  •  3
  •   Konamiman    15 年前

    如果我们遵守析构函数的“确定性”定义,那么我会说在.NET对象中没有析构函数,除非使用 the IDisposable interface .