Что такое деструктор класса

Что такое деструктор класса

Любой переменной, участвующей в работе программы, требуется память и некоторое начальное значение. Для переменных встроенных типов размещение в памяти обеспечивается компилятором. Для локальных переменных память выделяется из стека программы и занимается для хранения значения данной переменной до тех, пока не закончится время ее жизни. Сложные типы данных также должны размещаться в памяти и уничтожаться когда их время жизни закончилось. Это осуществляется с использованием конструкторов и деструкторов.

имя класса, предназначенная для уничтожения переменных (delete).

Одной из особенностей конструктора и деструктора является то, что в отличие от всех остальных функций, у них нет возвращаемого значения.

4.3.1. Конструкторы

Конструктор по умолчанию

Конструктор, не требующий аргументов, называется конструктором по умолчанию. Конструктор по умолчанию не имеет аргументов и инициализирует все переменные члены какими-либо начальными значениями.

При создании любого экземпляра класса вызывается конструктор. Если при описании экземпляра не указываются никакие параметры – вызывается конструктор по умолчанию:

Полный конструктор

Полный конструктор позволяет явно инициализировать все переменные-члены класса.

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

Неполный конструктор

Возможен и неполный конструктор, когда в списке параметров указываются не все возможные параметры для инициализации членов класса, а только наиболее часто используемые. Остальные параметры будут инициализированы значениями по умолчанию.

Инициализация переменных-членов класса в конструкторах может осуществляться не только в теле конструктора, но и после оператора :. При этом, во время присваивания переменной-члену значения, будет вызываться не оператор присваивания, а конструктор. Для встроенных типов данных, таких как double или int, это не существенно, но если членами класса являются абстрактные типы, вызов конструктора вместо оператора присваивания будет выполняться быстрее.

Конструктор копирования

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

4.3.2. Деструктор (пример 4.4. Конструктор и деструктор класса Матрица)

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

В классе Lens никакого динамического размещения не происходило, поэтому деструктор будет пустой, но его наличие все равно обязательно. Для примера реализации деструктора, представим, что имеется класс Matrix, который в конструкторе динамически создает двумерный массив размерности n x m. Тогда деструктор должен освобождать память, которую выделяет конструктор.

Конструктор вызывается в момент создания переменной, деструктор вызывается когда время жизни переменной закончилось, то есть когда встречается закрывающая фигурная скобка > блока, в которой была объявлен экземпляр класса, либо когда вызывается оператор delete при динамическом размещении экземпляра класса.

4.3.3. Проверка правильности параметров. Исключительные ситуации

Конструкторы должны проверять передаваемые им аргументы на корректность значений. Например, показатель преломления не может быть меньше 1. Что делать, если в конструктор были переданы неправильные параметры? Для этого в языке С++ существуют исключительные ситуации.

Класс exception является стандартным базовым классом C++ для всех исключений. Исключения можно сгенерировать в случае возникновения непредвиденной ошибки, например мы предполагаем что при вызове класса Lens никто не будет пытаться задать показатель преломления меньше 1, но при этом такая ситуация возможна, и это может привести к ошибке. Сгенерировать исключительную ситуацию можно при помощи оператора throw:

Для обработки возникшей исключительной ситуации используются try и catch блоки.

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

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

В результаты выполнения данного блока программы на экран выведется сообщение » Index of refraction should be greater than 1.».

Если никаких исключений в try-блоке не происходит, программа игнорирует его catch-обработчик.

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

Источник

12.9 – Деструкторы

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

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

Именование деструктора

Как и у конструкторов, у деструкторов есть особые правила именования:

Обратите внимание, что правило 2 подразумевает, что для каждого класса может существовать только один деструктор, поскольку нет возможности перегружать деструкторы, так как они не могут отличаться друг от друга на основе аргументов.

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

Пример деструктора

Давайте посмотрим на простой класс, который использует деструктор:

Совет

Если вы скомпилируете приведенный выше пример и получите следующую ошибку:

Эта программа дает следующий результат:

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

В конце main() объект ar выходит за пределы области видимости. Это вызывает вызов деструктора

Время выполнения конструктора и деструктора

Как упоминалось ранее, конструктор вызывается при создании объекта, а деструктор – при уничтожении объекта. В следующем примере мы используем инструкции cout внутри конструктора и деструктора, чтобы показать это:

Эта программа дает следующий результат:

RAII (Resource Acquisition Is Initialization, получение ресурса есть инициализация) – это метод программирования, при котором использование ресурсов привязано к времени жизни объектов с автоматической продолжительностью (например, нединамически выделяемые объекты). В C++ RAII реализован через классы с конструкторами и деструкторами. Ресурс (например, память, дескриптор файла или базы данных и т.д.) обычно приобретается в конструкторе объекта (хотя он может быть получен после создания объекта, если это имеет смысл). Затем этот ресурс можно использовать, пока объект жив. Ресурс освобождается в деструкторе при уничтожении объекта. Основное преимущество RAII заключается в том, что он помогает предотвратить утечку ресурсов (например, не освобождение памяти), поскольку все объекты, содержащие ресурсы, очищаются автоматически.

Класс IntArray в примере выше является примером класса, который реализует RAII – выделение в конструкторе, освобождение в деструкторе. std::string и std::vector – классы стандартной библиотеки, которые следуют принципу RAII – динамическая память приобретается при инициализации и автоматически очищается при уничтожении.

Предупреждение о функции exit()

Резюме

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

Источник

Методы завершения (руководство по программированию в C#)

Методы завершения (также называемые деструкторами) используются для любой необходимой окончательной очистки, когда сборщик мусора окончательно удаляет экземпляра класса. В большинстве случаев можно избежать написания метода завершения, используя System.Runtime.InteropServices.SafeHandle или производные классы для переноса любого неуправляемого дескриптора.

Примечания

Метод завершения можно также реализовать как определение тела выражения, как показано в следующем примере.

Метод завершения неявно вызывает метод Finalize для базового класса объекта. В связи с этим вызов метода завершения неявно преобразуется в следующий код:

Это означает, что метод Finalize вызывается рекурсивно для всех экземпляров цепочки наследования начиная с самого дальнего и заканчивая самым первым.

Не следует использовать пустые методы завершения. Если класс содержит метод завершения, то в очереди метода Finalize создается запись. Эта очередь обрабатывается сборщиком мусора. Когда сборщик мусора обрабатывает очередь, он вызывает каждый метод завершения. Ненужные методы завершения, включая пустые методы завершения, методы завершения, которые вызывают только метод завершения базового класса, или методы завершения, которые вызывают только условно порожденные методы, приводят к ненужному снижению производительности.

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

Использование методов завершения для освобождения ресурсов

Освобождение ресурсов явным образом

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

Дополнительные сведения об очистке ресурсов см. в следующих статьях:

Пример

Источник

Конструктор и деструктор класса в C++

Возможно вы заметили, что определяя класс, мы не можем инициализировать его поля (члены) в самом определении. Можно присвоить им значение, написав соответствующий метод класса и вызвав его, после создания объекта вне класса. Такой способ не совсем удобен, так как объявляя, допустим, 33 объекта класса нам придется 33 раза вызывать метод, который присваивает значения полям класса. Поэтому, как правило, для инициализации полей класса, а так же для выделения динамической памяти, используется конструктор.

Конструктор (от construct – создавать) – это особый метод класса, который выполняется автоматически в момент создания объекта класса. То есть, если мы пропишем в нем, какими значениями надо инициализировать поля во время объявления объекта класса, он сработает без “особого приглашения”. Его не надо специально вызывать, как обычный метод класса.

В строках 11 – 17 определяем конструктор: имя должно быть идентично имени класса; конструктор НЕ имеет типа возвращаемого значения (void в том числе). Один объект объявляется сразу во время определения класса – строка 25. При запуске программы, конструктор этого объекта сработает даже до входа в главную функцию. Это видно на следующем снимке:

Что такое деструктор класса. Смотреть фото Что такое деструктор класса. Смотреть картинку Что такое деструктор класса. Картинка про Что такое деструктор класса. Фото Что такое деструктор класса

Деструктор (от destruct – разрушать) – так же особый метод класса, который срабатывает во время уничтожения объектов класса. Чаще всего его роль заключается в том, чтобы освободить динамическую память, которую выделял конструктор для объекта. Имя его, как и у конструктора, должно соответствовать имени класса. Только перед именем надо добавить символ

Добавим деструктор в предыдущий код. И создадим в классе два конструктора: один будет принимать параметры, второй – нет.

Источник

Деструкторы (C++)

). Например, деструктор для класса String объявляется следующим образом:

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

Рассмотрим следующее объявление класса String :

В предыдущем примере деструктор String::

String использует delete оператор для освобождения пространства, динамически выделяемого для хранения текста.

Объявление деструкторов

Деструкторы — это функции с тем же именем, что и класс, но с добавленным в начало знаком тильды (

При объявлении деструкторов действуют несколько правил. Деструкторы:

Не могут иметь аргументов.

Не возвращают значение (или void ).

Использование деструкторов

Деструкторы вызываются, когда происходит одно из следующих событий:

Локальный (автоматический) объект с областью видимости блока выходит за пределы области видимости.

Время существования временного объекта заканчивается.

Программа заканчивается, глобальные или статические объекты продолжают существовать.

Деструктор явно вызываться с использованием полного имени функции деструктора.

Деструкторы могут свободно вызывать функции-члена класса и осуществлять доступ к данным членов класса.

Существуют два ограничения на использование деструкторов.

Вы не можете получить его адрес.

Производные классы не наследуют деструктор своего базового класса.

Порядок уничтожения

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

Вызывается деструктор класса, и выполняется тело функции деструктора.

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

Деструкторы для невиртуальных базовых классов вызываются в обратную последовательность объявления.

Деструкторы для виртуальных базовых классов вызываются в порядке, обратном порядку их объявления.

Виртуальные базовые классы

Деструкторы для виртуальных базовых классов вызываются в порядке, обратном их указанию в направленном ациклическом графе (в глубину, слева направо, обход в обратном порядке). На следующем рисунке представлен граф наследования.

Что такое деструктор класса. Смотреть фото Что такое деструктор класса. Смотреть картинку Что такое деструктор класса. Картинка про Что такое деструктор класса. Фото Что такое деструктор класса
Граф наследования, показывающий виртуальные базовые классы

Ниже перечислены заголовки классов, представленных на рисунке.

Просмотрите левую часть графа, начиная с самой глубокой точки графа (в данном случае E ).

Просматривайте граф справа налево, пока не будут пройдены все узлы. Запомните имя текущего узла.

Пересмотрите предыдущий узел (вниз и вправо), чтобы определить, является ли рассматриваемый узел виртуальным базовым классом.

Если рассматриваемый узел является виртуальным базовым классом, просмотрите список, чтобы проверить, был ли он введен ранее. Если он не является виртуальным базовым классом, игнорируйте его.

Если рассматриваемого узла еще нет в списке, добавьте его вниз списка.

Просмотрите граф вверх и вдоль следующего пути вправо.

Перейдите к шагу 2.

Если путь последний путь вверх исчерпан, запомните имя текущего узла.

Перейдите к шагу 3.

Выполняйте этот процесс, пока нижний узел снова не станет текущим узлом.

Таким образом, для класса E порядок удаления будет следующим.

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

Порядок построения или удаления очень важен, когда конструкторы и деструкторы в одном классе полагаются на другой компонент, который создается первым или сохраняется дольше, например если деструктор A (на рисунке выше) полагается на то, что B будет по-прежнему присутствовать после выполнения кода, или наоборот.

Такие взаимозависимости между классами в графе наследования опасны, поскольку классы, наследуемые впоследствии, могут изменить крайний левый путь, тем самым изменив порядок построения и удаления.

Не являющиеся виртуальными базовыми классами

Деструкторы для невиртуальных базовых классов вызываются в порядке, в котором объявляются имена базовых классов. Рассмотрим следующее объявление класса.

Явные вызовы деструктора

Редко возникает необходимость в явном вызове деструктора. Однако может быть полезно выполнить удаление объектов, размещенных по абсолютным адресам. Обычно эти объекты выделяются с помощью определяемого пользователем new оператора, принимающего аргумент размещения. delete Оператор не может освободить эту память, так как она не выделена из бесплатного хранилища (Дополнительные сведения см. delete ). Вызов деструктора, однако, может выполнить соответствующую очистку. Для явного вызова деструктора для объекта ( s ) класса String воспользуйтесь одним из следующих операторов.

Нотация для явных вызовов деструкторов, показанная в предыдущем примере, может использоваться независимо от того, определяет ли тип деструктор. Это позволяет выполнять такие явные вызовы, не зная, определен ли деструктор для типа. Явный вызов деструктора, если ни один из них не определен, не имеет никакого эффекта.

Отказоустойчивость

Классу требуется деструктор, если он получает ресурс, и для безопасного управления ресурсом, вероятно, потребуется реализовать конструктор копии и назначение копирования.

Если эти специальные функции не определены пользователем, они неявно определяются компилятором. Неявно созданные конструкторы и операторы присваивания выполняют поверхностную почленном копию, которая почти наверняка неверно, если объект управляет ресурсом.

Явное определение деструктора, конструктора копирования или оператора присваивания копирования предотвращает неявное определение конструктора перемещения и оператора присваивания перемещения. В этом случае не удастся предоставить операции перемещения, если копирование занимает много ресурсов, но пропущенная возможность оптимизации.

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *