Разница между деструктором и финализатором?

Обратите внимание: этот вопрос касается разницы в терминологии между словами "деструктор" и "финализатор" и их правильного использования. Я просто привел примеры их использования в С# и С++/CLI, чтобы показать, почему я задаю вопрос. Я хорошо знаю, как это реализовано как в С#, так и в CLR, но я спрашиваю о правильном использовании терминологии.


В мире С# термины "деструктор" и "финализатор", по-видимому, используются в значительной степени взаимозаменяемо, что, как я подозреваю, связано с тем, что спецификация С# описывает недетерминированные функции очистки с использованием слова "деструктор", тогда как документация CLR всегда использует слово "финализатор", поэтому в пределах С# они означают одно и то же.

Однако в спецификации С++/CLI существует различие между ними. Он допускает как детерминированную, так и недетерминированную очистку и использует термин "деструктор" для детерминированной функциональности и "финализатор" для недетерминированной функциональности:

Финализатор обеспечивает недетерминированную очистку. Финализатор - это функция "последнего шанса", которая выполняется во время сбора мусора, обычно на объекте, деструктор которого не был выполнен.

Кроме того, описания Википедии destructor и finalizer указывают, что деструкторы и финализаторы являются отдельными понятиями и поддерживают использование С++/CLI терминов в отношении детерминизма:

В отличие от деструкторов, финализаторы не детерминированы. Деструктор запускается, когда программа явно освобождает объект. Финализатор, напротив, выполняется, когда внутренняя система сбора мусора освобождает объект.

Вопросы:

  • Существует ли с точки зрения компьютерной науки четко определенная разница между "деструктором" и "финализатором", или терминологией является то, что может быть определено только контекстно?

  • Если есть четко определенная разница, то почему С# spec использует "неправильную" терминологию?

Ответ 1

1) Существует ли четко определенная разница между "деструктором" и "финализатором", используемым в промышленности или научном сообществе?

Конечно, похоже. Разница заключается в том, что деструкторы - это методы очистки, которые вызываются детерминистически, тогда как финализаторы запускаются, когда сообщается сборщику мусора.

2) В этом случае спецификация С# ошибочна - финализаторы называются деструкторами в С#. Почему авторы спецификации С# ошибались?

Я не знаю, но могу догадаться. На самом деле у меня есть две догадки.

Угадайте № 1, что 12 мая 1999 года не было статьи в википедии, в которой четко описывалась тонкая разница между этими двумя понятиями. Это потому, что не было википедии. Помните, когда не было википедии? Темные века, мужик. Ошибка может быть просто честной ошибкой, полагая, что эти два термина были идентичны.

Чек, насколько я знаю, эти два термина были идентичны 12 мая 1999 года, а разница в определениях была развита позже, так как стало очевидно, что существует необходимость устранения двусмысленности между нетерпеливыми и ленивыми методами очистки.

Угадайте, что 2 мая 12 мая 1999 года комитет по дизайну языка пожелал оставить открытой возможность того, что "деструктор" может быть реализован как нечто, отличное от финализатора. То есть, "деструктор" был разработан как концепция языка С#, которая не обязательно сопоставляла один-к-одному с концепцией "финализатор".NET. При разработке языка в то же время, что и структура, на которой он сидит, также разрабатывается, иногда вы хотите изолировать себя от поздних изменений дизайна в ваших подсистемах.

Записи языкового комитета за 12 мая 1999 года частично читаются:

Мы будем использовать термин "деструктор" для члена, который выполняет когда экземпляр возвращен. Классы могут иметь деструкторы; Структуры не могут. В отличие от С++, деструктор не может быть явно. Уничтожение не детерминированный - вы не можете надежно знать, когда деструктор выполнит, кроме того, что он выполняется на некоторых после всех ссылок на объект был выпущен. деструкторы в цепочке наследования вызываются по порядку, от большинства потомка к наименее потомству. Там не требуется (и никоим образом) для класса, чтобы явным образом вызвать базовый деструктор. Компилятор С# компилирует деструкторы к соответствующее представление CLR. Для эта версия, вероятно, означает финализатор экземпляра, который выделенных в метаданных. CLR может предоставлять статические финализаторы в будущее; мы не видим никаких препятствий для С# с использованием статических финализаторов.

Итак, теперь вы знаете все, что я знаю по этому вопросу. Если вы хотите узнать больше, спросите Андерса в следующий раз, когда увидите его.

Ответ 2

Строго говоря, у С# нет деструктора (я считаю, что спецификация С# путается в этой точке). Финализатор С# выглядит как деструктор С++, но, как вы говорите, не детерминирован. С# имеет детерминированную очистку в виде IDisposable::Dispose (но это все еще не называется деструктором).

С++/CLI имеет детерминированные деструкторы, которые выглядят как деструкторы С++. На уровне CLI эти карты на IDisposable::Dispose() (IDisposable реализованы для вас). С++/CLI имеет недетерминированные финализаторы, которые выглядят как деструкторы, но используют! префикс вместо префикса ^.

Тот факт, что С++/CLI использует тот же синтаксис для деструкторов, что С# использует для финализаторов, может быть немного запутанным - но он лучше подходит для С++, который имеет сильную традицию детерминированного уничтожения.

К сожалению, отсутствие универсальных определений этих терминов означает, что вам всегда нужно разъяснять, о чем вы говорите. Лично я всегда использую слово finalizer, когда говорю о концепции С# и резервирует деструктор для контекстов, где он определенно подразумевает детерминированное уничтожение.

[Обновление] Поскольку мой первоначальный пост здесь, Эрик Липперт опубликовал свой ответ (принятый ответ), а затем опубликовал сообщение в блоге. Я рад видеть, что мы согласны: -)

Ответ 3

Я считаю, что "деструктор" - это код С#, а "финализатор" - это скомпилированный метод CIL. Компилятор С# превращает деструктор в финализатор.

EDIT: быть более подробным; Спецификация языка С# определяет "деструктор" как метод экземпляра С# для класса. "destructor", тогда, является частью грамматики С# - деструкторы являются лингвистическим объектом, появляющимся в исходном коде.

Деструктор - это член, который реализует действия, необходимые для уничтожения экземпляра класса. Деструкторы не могут иметь параметры, они не могут иметь модификаторы доступности, и они не могут быть вызваны явно. Деструктор экземпляра автоматически запускается во время сбора мусора.

"Финализатор" - это термин, используемый во время выполнения Common Language Runtime, например, при вызовах GC.WaitForPendingFinalizers(), и он относится к любому языку .net, а не только к С#. Любой тип ссылки .net может иметь финализатор. Для класса С# (артефакт исходного кода) деструктор компилируется в метод CIL, который является финализатором типа CLR.

Или более лаконично, деструктор - финализатор, поскольку исходный код - машинный код;)

Ответ 4

Если мы будем придерживаться "детерминированного" определения деструкторов, я бы сказал, что в объектах .NET нет деструкторов, если явно не реализовано с помощью IDisposable интерфейс.