Финализатор - Finalizer

В Информатика, а финализатор или же завершить метод это особенный метод который выполняет завершение, как правило, некоторая форма очистки. Финализатор выполняется во время разрушение объекта, до того, как объект будет освобожден, и дополняет инициализатор, который выполняется во время создание объекта, следующий распределение. Некоторые настоятельно не рекомендуют финализаторы из-за трудностей в правильном использовании и сложности, которую они добавляют, и вместо них предлагаются альтернативы, в первую очередь шаблон утилизации[1] - видеть проблемы с финализаторами.

Термин «финализатор» в основном используется в объектно-ориентированный и функциональные языки это использование вывоз мусора, из которых архетип Болтовня. Это контрастирует с "деструктор ", который является методом финализации в языках с детерминированным временем жизни объекта, архетипично C ++.[2][3] Как правило, они являются эксклюзивными - у языка будут либо финализаторы (при автоматическом сборке мусора), либо деструкторы (при ручном управлении памятью), но в редких случаях язык может иметь оба, как в C ++ / CLI и D, а в случае подсчет ссылок (вместо отслеживания сборки мусора) терминология меняется. В техническом использовании термин «финализатор» также может использоваться для обозначения деструкторов, поскольку они также выполняют финализацию, и при этом проводятся некоторые более тонкие различия - см. терминология. Термин «окончательный» также используется для обозначения класса, который не может быть унаследованный; это не связано.

Терминология

Терминология «финализатор» и «финализация» по сравнению с «деструктором» и «уничтожением» варьируется у разных авторов и иногда неясна.

В обычном использовании деструктор метод, вызываемый детерминированно при разрушении объекта, архетип - деструкторы C ++; в то время как финализатор вызывается сборщиком мусора недетерминированно, а архетип - Java завершить методы.

Для языков, реализующих сборку мусора через подсчет ссылок, терминология меняется в зависимости от некоторых языков, например Цель-C и Perl, использующий «деструктор», и другие языки, такие как Python, использующий «финализатор» (согласно спецификации, Python собирает мусор, но ссылка CPython реализация, начиная с версии 2.0, использует комбинацию подсчета ссылок и сборки мусора). Это отражает тот факт, что подсчет ссылок приводит к полудетерминированному времени жизни объекта: для объектов, которые не являются частью цикла, объекты уничтожаются детерминированно, когда счетчик ссылок падает до нуля, но объекты, которые являются частью цикла, уничтожаются недетерминированно. , как часть отдельной формы сборки мусора.

В определенном узком техническом использовании, «конструктор» и «деструктор» являются терминами уровня языка, означающими «методы, определенные в классе», тогда как «инициализатор» и «финализатор» являются терминами уровня реализации, означающими «методы, вызываемые во время создания объекта или разрушение ". Так, например, в исходной спецификации языка C # упоминались «деструкторы», хотя C # собирает мусор, но спецификация для Инфраструктура общего языка (CLI) и реализация его среды выполнения как общеязыковая среда выполнения (CLR), называется «финализаторы». Это отражено в примечаниях комитета по языку C #, которые частично гласят: «Компилятор C # компилирует деструкторы в ... [вероятно] финализатор [ы] экземпляров».[4][5] Эта терминология сбивает с толку, и поэтому в более поздних версиях спецификации C # метод уровня языка называется «финализаторами».[6]

Другой язык, который не делает этого терминологического различия, - D. Хотя классы D собираются сборщиком мусора, их функции очистки называются деструкторами.[7]

Использовать

Финализация в основном используется для очистки, для освобождения памяти или других ресурсов: для освобождения памяти, выделенной через ручное управление памятью; очистить ссылки, если подсчет ссылок используется (уменьшает количество ссылок); высвободить ресурсы, особенно в Приобретение ресурсов - это инициализация (RAII) идиома; или отменить регистрацию объекта. Объем финализации значительно различается между языками, от обширной финализации в C ++, который имеет ручное управление памятью, подсчет ссылок и детерминированное время жизни объектов; часто без финализации в Java, которая имеет недетерминированное время жизни объектов и часто реализуется с помощью сборщика мусора. Также возможно, что явная (определяемая пользователем) финализация будет незначительной или совсем не будет, но будет значительная неявная финализация, выполняемая компилятором, интерпретатором или средой выполнения; это обычное дело в случае автоматического подсчета ссылок, как в CPython эталонная реализация Python или в Автоматический подсчет ссылок в реализации Apple Цель-C, которые автоматически разрывают ссылки во время финализации. Финализатор может включать произвольный код; особенно сложное использование - автоматическое возвращение объекта в пул объектов.

Освобождение памяти во время финализации является обычным явлением в таких языках, как C ++, где ручное управление памятью является стандартным, но также происходит и в управляемых языках, когда память выделяется вне управляемой кучи (вне языка); в Java это происходит с Собственный интерфейс Java (JNI) и ByteBuffer объекты в Новый ввод / вывод (НИО). Последнее может вызвать проблемы из-за того, что сборщик мусора не может отслеживать эти внешние ресурсы, поэтому они не будут собираться достаточно агрессивно и могут вызвать ошибки нехватки памяти из-за исчерпания неуправляемой памяти - этого можно избежать, если обработать собственные память как ресурс и использование шаблон утилизации, как описано ниже.

Финализаторы обычно гораздо менее необходимы и используются гораздо реже, чем деструкторы. Они гораздо менее необходимы, потому что сборка мусора автоматизирует управление памятью, и гораздо реже используются, потому что они обычно не выполняются детерминированно - они не могут быть вызваны своевременно или даже вообще, а среда выполнения не может быть предсказана - и, следовательно, любая очистка, которая должна выполняться детерминированным способом, должна вместо этого можно сделать другим способом, чаще всего вручную через шаблон утилизации. Примечательно, что и Java, и Python не гарантируют, что финализаторы когда-либо будут вызваны, и поэтому на них нельзя полагаться при очистке.

Из-за отсутствия контроля со стороны программиста над их выполнением обычно рекомендуется избегать финализаторов для любых, кроме самых тривиальных, операций. В частности, операции, часто выполняемые в деструкторах, обычно не подходят для финализаторов. Обычный антипаттерн заключается в том, чтобы писать финализаторы, как если бы они были деструкторами, что одновременно не нужно и неэффективно из-за различий между финализаторами и деструкторами. Это особенно распространено среди C ++ программисты, так как деструкторы широко используются в идиоматическом C ++, следуя Приобретение ресурсов - это инициализация (RAII) идиома.

Синтаксис

Языки программирования, использующие финализаторы, включают C ++ / CLI, C #, Чистый, Идти, Ява, и Python. Синтаксис значительно зависит от языка.

В Java финализатор - это метод, называемый завершить, который отменяет Object.finalize метод.[8]

В Python финализатор - это метод, называемый __del__.

В Perl финализатор - это метод, называемый РАЗРУШАТЬ.

В C # финализатор (называемый «деструктором» в более ранних версиях стандарта) - это метод, имя которого является именем класса с ~ с префиксом, как в ~ Фу - это тот же синтаксис, что и в C ++ деструктор, и эти методы изначально назывались «деструкторами» по аналогии с C ++, несмотря на другое поведение, но были переименованы в «финализаторы» из-за возникшей путаницы.[6]

В C ++ / CLI, который имеет как деструкторы, так и финализаторы, деструктор - это метод, имя которого является именем класса с ~ с префиксом, как в ~ Фу (как в C #), а финализатор - это метод, имя которого является именем класса с ! с префиксом, как в ! Foo.

В Go финализаторы применяются к одному указателю путем вызова runtime.SetFinalizer функция в стандартной библиотеке.[9]

Выполнение

Финализатор вызывается, когда объект сборщик мусора - после того, как объект стал мусором (недоступен), но до того, как его память будет освобождена. Финализация происходит недетерминированно, по усмотрению сборщика мусора и может никогда не произойти. Это контрастирует с деструкторами, которые вызываются детерминированно, как только объект больше не используется, и вызываются всегда, за исключением случая неконтролируемого завершения программы. Финализаторы чаще всего методы экземпляра, из-за необходимости выполнять операции с объектами.

Сборщик мусора также должен учитывать возможность воскрешения объекта. Чаще всего это делается путем первого запуска финализаторов, затем проверки, были ли воскрешены какие-либо объекты, и, если да, отмены их уничтожения. Эта дополнительная проверка потенциально дорогостоящая - простая реализация повторно проверяет весь мусор, если хотя бы один объект имеет финализатор - и, таким образом, замедляет и усложняет сборку мусора. По этой причине объекты с финализаторами могут собираться реже, чем объекты без финализаторов (только в определенных циклах), что усугубляет проблемы, вызванные зависимостью от своевременного завершения, такие как утечки ресурсов.

Если объект воскресает, возникает дополнительный вопрос, будет ли его финализатор вызван снова, когда он будет уничтожен в следующий раз - в отличие от деструкторов, финализаторы потенциально вызываются несколько раз. Если для воскрешенных объектов вызываются финализаторы, объекты могут многократно воскрешать себя и быть неразрушаемыми; это происходит в реализации Python CPython до Python 3.4, а также в языках CLR, таких как C #. Чтобы избежать этого, на многих языках, включая Java, Objective-C (по крайней мере, в последних реализациях Apple) и Python из Python 3.4, объекты финализируются не чаще одного раза, что требует отслеживания, был ли объект еще завершен.

В других случаях, особенно в языках CLR, таких как C #, финализация отслеживается отдельно от самих объектов, и объекты могут повторно регистрироваться или отменяться для завершения.

Проблемы

Финализаторы могут вызвать значительное количество проблем, поэтому ряд властей настоятельно не одобряют их.[10][11] Эти проблемы включают:[10]

  • Финализаторы не могут быть вызваны своевременно или вообще не могут быть вызваны, поэтому на них нельзя полагаться в отношении сохранения состояния, высвобождения ограниченных ресурсов или выполнения каких-либо других важных действий.
  • Финализаторы могут привести к воскрешение объекта, которая часто является ошибкой программирования и сама возможность которой значительно замедляет и усложняет сборку мусора.
  • Финализаторы запускаются на основе сборки мусора, которая обычно основана на управляемой нехватке памяти - они не запускаются в случае нехватки других ресурсов и, следовательно, не подходят для управления другими дефицитными ресурсами.
  • Финализаторы не работают в указанном порядке и не могут полагаться на инварианты классов (поскольку они могут относиться к другим объектам, которые уже были завершены).
  • Медленные финализаторы могут задерживать другие финализаторы.
  • Исключения в финализаторах обычно невозможно обработать, потому что финализатор запускается в неопределенной среде и может либо игнорироваться, либо вызывать неконтролируемое завершение программы.
  • Финализаторы могут ссылаться на живые объекты и случайно финализировать их, нарушая инварианты программы.
  • Финализаторы могут вызвать проблему синхронизации, даже в других последовательных (однопоточных) программах, поскольку финализация может выполняться одновременно (конкретно, в одном или нескольких отдельных потоках).[12]
  • Финализаторы могут вызвать взаимоблокировку, если используются механизмы синхронизации, такие как блокировки, из-за того, что они не выполняются в указанном порядке и, возможно, выполняются одновременно.
  • Финализаторы, которые запускаются во время завершения программы, не могут полагаться на обычную среду выполнения и, следовательно, могут выйти из строя из-за неправильных предположений - по этой причине финализаторы часто не запускаются во время завершения.

Кроме того, финализаторы могут не запускаться из-за того, что объект остается доступным после того, как ожидается, что они будут мусором, либо из-за ошибок программирования, либо из-за неожиданной достижимости. Например, когда Python перехватывает исключение (или исключение не перехватывается в интерактивном режиме), он сохраняет ссылку на кадр стека, в котором возникло исключение, что сохраняет объекты, на которые ссылается этот кадр стека, в действии.

Финализаторы в суперклассе также могут замедлять сборку мусора в подклассе, так как финализатор потенциально может ссылаться на поля в подклассе, и, таким образом, поле не может быть собрано сборщиком мусора до следующего цикла после запуска финализатора.[10] Этого можно избежать, используя композиция выше наследования.

Управление ресурсами

Обычный антипаттерн заключается в использовании финализаторов для освобождения ресурсов по аналогии с Приобретение ресурсов - это инициализация (RAII) идиома C ++: получить ресурс в инициализаторе (конструкторе) и освободить его в финализаторе (деструкторе). Это не работает по ряду причин. По сути, финализаторы могут никогда не вызываться, и даже если они вызваны, они могут не вызываться своевременно - таким образом, использование финализаторов для освобождения ресурсов обычно вызывает утечки ресурсов. Кроме того, финализаторы не вызываются в предписанном порядке, тогда как ресурсы часто нужно освобождать в определенном порядке, часто в порядке, обратном тому, в котором они были получены. Кроме того, поскольку финализаторы вызываются по усмотрению сборщика мусора, они часто будут вызываться только при нехватке управляемой памяти (когда доступно мало управляемой памяти), независимо от нагрузки на ресурсы - если скудные ресурсы удерживаются мусором, но их много доступной управляемой памяти, сборка мусора может не произойти, поэтому эти ресурсы не будут восстановлены.

Таким образом, вместо использования финализаторов для автоматического управления ресурсами в языках со сборкой мусора необходимо вручную управлять ресурсами, обычно с помощью шаблон утилизации. В этом случае ресурсы все еще могут быть получены в инициализаторе, который вызывается явно при создании экземпляра объекта, но освобождается в методе удаления. Метод dispose может быть вызван явно или неявно языковыми конструкциями, такими как C # с помощью, Java пытаться-with-resources или Python с.

Однако в некоторых случаях для освобождения ресурсов используются и шаблон удаления, и финализаторы. Это в основном встречается в языках CLR, таких как C #, где финализация используется в качестве резервной копии для удаления: когда ресурс получен, получающий объект ставится в очередь для завершения, так что ресурс освобождается при уничтожении объекта, даже если ресурс не выпущен путем ручной утилизации.

Детерминированное и недетерминированное время жизни объекта

В языках с детерминированным временем жизни объекта, особенно в C ++, управление ресурсами часто осуществляется путем привязки времени жизни владения ресурсом к времени жизни объекта, получения ресурсов во время инициализации и освобождения их во время финализации; это известно как Приобретение ресурсов - это инициализация (RAII). Это гарантирует, что владение ресурсами инвариант класса, и эти ресурсы высвобождаются сразу после уничтожения объекта.

Однако в языках с недетерминированным временем жизни объекта - которые включают все основные языки со сборкой мусора, такие как C #, Java и Python - это не работает, потому что финализация может быть несвоевременной или может не произойти вообще, и, следовательно, ресурсы могут не выпускаться в течение длительного времени или даже вообще, что вызывает утечки ресурсов. Вместо этого на этих языках ресурсы обычно управляются вручную через шаблон утилизации: ресурсы могут быть получены во время инициализации, но высвобождаются путем вызова избавляться метод. Тем не менее, использование финализации для выпуска ресурсов на этих языках является обычным антипаттерн, и забывая позвонить избавляться по-прежнему вызовет утечку ресурсов.

В некоторых случаях оба метода комбинируются, используя явный метод удаления, но также освобождая все еще удерживаемые ресурсы во время финализации в качестве резервной копии. Это обычно встречается в C # и реализуется путем регистрации объекта для завершения всякий раз, когда ресурс приобретается, и подавления завершения всякий раз, когда ресурс освобождается.

Воскрешение объекта

Если указанные пользователем финализаторы разрешены, финализация может вызвать воскрешение объекта, поскольку финализаторы могут запускать произвольный код, который может создавать ссылки от живых объектов на уничтожаемые объекты. Для языков без сборки мусора это серьезная ошибка и вызывает висячие ссылки и безопасность памяти нарушения; для языков со сборкой мусора это предотвращается сборщиком мусора, чаще всего путем добавления еще одного шага к сборке мусора (после запуска всех указанных пользователем финализаторов проверяйте восстановление), что усложняет и замедляет сборку мусора.

Кроме того, воскрешение объекта означает, что объект не может быть уничтожен, а в патологических случаях объект всегда может воскресить себя во время завершения, сделав себя неразрушимым. Чтобы предотвратить это, некоторые языки, такие как Java и Python (начиная с Python 3.4), завершают объекты только один раз и не завершают воскрешенные объекты. Конкретно это делается путем отслеживания того, был ли объект завершен на индивидуальной основе. Objective-C также отслеживает финализацию (по крайней мере, в последних версиях Apple) по аналогичным причинам, рассматривая воскрешение как ошибку.

Другой подход используется в .NET Framework, особенно C # и Visual Basic .NET, где финализация отслеживается "очередью", а не объектом. В этом случае, если предоставляется указанный пользователем финализатор, по умолчанию объект финализируется только один раз (он ставится в очередь для завершения при создании и удаляется из очереди после завершения), но это можно изменить, вызвав GC модуль. Завершение можно предотвратить, позвонив GC.SuppressFinalize, который удаляет объект из очереди или повторно активирует вызовом GC.ReRegisterForFinalize, который ставит объект в очередь. Они особенно используются при использовании финализации для управления ресурсами в качестве дополнения к шаблону удаления или при реализации пул объектов.

Контраст с инициализацией

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

Помимо присвоения начальных значений, инициализация в основном используется для получения ресурсов или для регистрации объекта в какой-либо службе (например, обработчик события ). Эти действия имеют симметричные действия по освобождению или отмене регистрации, и они могут симметрично обрабатываться в финализаторе, что выполняется в RAII. Однако во многих языках, особенно в языках со сборкой мусора, время жизни объекта асимметрично: создание объекта происходит детерминированно в некоторой явной точке кода, но разрушение объекта происходит недетерминированно, в некоторой неопределенной среде, по усмотрению сборщика мусора. Эта асимметрия означает, что финализация не может эффективно использоваться в качестве дополнения к инициализации, потому что она не происходит своевременно, в указанном порядке или в указанной среде. Симметрия частично восстанавливается также путем удаления объекта в явной точке, но в этом случае удаление и уничтожение не происходят в одной и той же точке, и объект может находиться в состоянии «утилизирован, но все еще жив», что ослабляет инварианты классов и усложняет использование.

Переменные обычно инициализируются в начале своего жизненного цикла, но не завершаются в конце своего жизненного цикла - хотя, если переменная имеет объект в качестве значения, объект могут быть доработаны. В некоторых случаях переменные также финализируются: расширения GCC позволяют финализировать переменные.

Связь с наконец-то

Как отражено в наименовании, "доработка" и наконец-то Конструкция выполняет схожие цели: выполняет какое-то заключительное действие, как правило, очистку после того, как что-то еще было завершено. Они отличаются тем, когда они возникают - наконец-то предложение выполняется, когда выполнение программы покидает тело связанного пытаться предложение - это происходит во время раскрутки стека, и, таким образом, есть стек ожидающих наконец-то предложения по порядку - в то время как завершение происходит при уничтожении объекта, что происходит в зависимости от метода управления памятью, и в целом существует просто набор объектов, ожидающих завершения - часто в куче - что не обязательно должно происходить в каком-либо конкретном порядке.

Однако в некоторых случаях они совпадают. В C ++ разрушение объекта детерминировано, и поведение объекта наконец-то предложение может быть создано с помощью локальной переменной с объектом в качестве значения, область видимости которого является блоком, соответствующим телу пытаться предложение - объект завершается (уничтожается), когда выполнение выходит из этой области, точно так же, как если бы был наконец-то пункт. По этой причине C ++ не имеет наконец-то конструкция - разница в том, что финализация определяется в определении класса как метод деструктора, а не на месте вызова в наконец-то пункт.

Наоборот, в случае наконец-то пункт в сопрограмма, как и в генераторе Python, сопрограмма может никогда не завершиться - только когда-либо уступить - и, следовательно, при обычном выполнении наконец-то пункт никогда не выполняется. Если интерпретировать экземпляры сопрограммы как объекты, то наконец-то предложение можно рассматривать как финализатор объекта и, таким образом, может выполняться, когда экземпляр собирается сборщиком мусора. В терминологии Python определение сопрограммы - это генератор. функция а его экземпляр - генератор итератор и таким образом наконец-то Предложение в функции генератора становится финализатором в итераторах генератора, созданных из этой функции.

История

Понятие финализации как отдельного шага в уничтожении объекта восходит к Монтгомери (1994),[13] по аналогии с более ранним различием инициализации при построении объекта в Мартин и Оделл (1992).[14] В литературе до этого момента для этого процесса использовалось «разрушение», не различая финализации и освобождения, а в языках программирования, относящихся к этому периоду, таких как C ++ и Perl, использовался термин «разрушение». Термины «завершение» и «завершение» также используются во влиятельной книге. Шаблоны проектирования (1994).[а][15] Появление Java в 1995 году содержало завершить методы, которые популяризировали этот термин и связали его со сборкой мусора, и языки с этого момента обычно делают это различие и используют термин «завершение», особенно в контексте сборки мусора.


Смотрите также

Примечания

  1. ^ Опубликовано в 1994 г. с авторским правом 1995 г.

Рекомендации

  1. ^ Джаггер, Перри и Сестофт 2007, п.542, "В C ++ деструктор вызывается определенным образом, тогда как в C # финализатор - нет. Чтобы получить определенное поведение из C #, следует использовать Утилизируйте.
  2. ^ Бём, Ханс-Дж. (2002). Деструкторы, финализаторы и синхронизация. ПОПЛ.
  3. ^ Джаггер, Перри и Сестофт 2007, п.542, Деструкторы C ++ против финализаторов C # Деструкторы C ++ детерминированы в том смысле, что они запускаются в известные моменты времени, в известном порядке и из известного потока. Таким образом, они семантически очень отличается от финализаторов C #, которые запускаются в неизвестные моменты времени, в неизвестном порядке, из неизвестного потока и по усмотрению сборщика мусора.
  4. ^ В полном объеме: «Мы собираемся использовать термин« деструктор »для члена, который выполняется, когда экземпляр восстанавливается. Классы могут иметь деструкторы; структуры не могут. В отличие от C ++, деструктор не может быть вызван явно. Разрушение не -детерминированный - вы не можете достоверно знать, когда будет выполняться деструктор, за исключением того, чтобы сказать, что он выполняется в какой-то момент после того, как все ссылки на объект были освобождены. Деструкторы в цепочке наследования вызываются по порядку, от большинства потомков до наименее потомок. В производном классе нет необходимости (и нет возможности) явно вызывать базовый деструктор. Компилятор C # компилирует деструкторы в соответствующее представление CLR. Для этой версии это, вероятно, означает финализатор экземпляра, который выделяется в метаданных. CLR может предоставлять статические финализаторы в будущем; мы не видим никаких препятствий для использования C # статических финализаторов », 12 мая 1999 г.
  5. ^ В чем разница между деструктором и финализатором?, Эрик Липперт, Блог Эрика Липперта: «Сказочные приключения в программировании», 21 января 2010 г.
  6. ^ а б Джаггер, Перри и Сестофт 2007, п.542, «В предыдущей версии этого стандарта то, что теперь называется« финализатор », называлось« деструктором ». Опыт показал, что термин« деструктор »вызывал путаницу и часто приводил к неверным ожиданиям, особенно для программистов, знающих C ++. . В C ++ деструктор вызывается определенным образом, тогда как в C # финализатор - нет. Чтобы получить определенное поведение из C #, следует использовать Утилизируйте."
  7. ^ Деструкторы классов Деструкторы классов в D
  8. ^ java.lang, объект класса: завершить
  9. ^ https://golang.org/pkg/runtime/#SetFinalizer
  10. ^ а б c "MET12-J. Не использовать финализаторы ", Дхрув Мохиндра, Стандарт безопасного кодирования CERT Oracle для Java, 05. Методы (MET)
  11. ^ объект .__ del __ (сам), Справочник по языку Python, 3. Модель данных: "... __del __ () методы должны делать абсолютный минимум, необходимый для поддержания внешних инвариантов ".
  12. ^ Ганс-Дж. Бём, Завершение, потоки и модель памяти на основе технологии Java ™, Конференция JavaOne, 2005.
  13. ^ Монтгомери 1994, п.120, "Как и в случае создания экземпляров объекта, при проектировании завершения объекта может быть полезна реализация двух операций для каждого класса: завершить и прекратить операция. Операция finalize разрывает ассоциации с другими объектами, обеспечивая целостность структуры данных ".
  14. ^ Монтгомери 1994, п.119, "Рассмотрите реализацию создания экземпляров класса как Создайте и инициализировать операция, как предложили Мартин и Оделл. Первый выделяет память для новых объектов, а второй конструирует объект в соответствии со спецификациями и ограничениями ».
  15. ^ "Каждый новый класс имеет фиксированные накладные расходы на реализацию (инициализация, завершение и т. Д.).", "деструктор В C ++ - операция, которая автоматически вызывается для завершения объекта, который будет удален ".

дальнейшее чтение

внешняя ссылка