сколько параметров можно передать в деструктор
Деструкторы (C++)
). Например, деструктор для класса String объявляется следующим образом:
Если деструктор не определен, компилятор будет предоставлять его по умолчанию. для многих классов это достаточно. Необходимо определить пользовательский деструктор, если класс хранит дескрипторы для системных ресурсов, которые необходимо освободить, или указатели, владеющие памятью, на которую они указывают.
Рассмотрим следующее объявление класса String :
В предыдущем примере деструктор String::
String использует delete оператор для освобождения пространства, динамически выделяемого для хранения текста.
Объявление деструкторов
Деструкторы — это функции с тем же именем, что и класс, но с добавленным в начало знаком тильды (
При объявлении деструкторов действуют несколько правил. Деструкторы:
Не могут иметь аргументов.
Не возвращают значение (или void ).
Использование деструкторов
Деструкторы вызываются, когда происходит одно из следующих событий:
Локальный (автоматический) объект с областью видимости блока выходит за пределы области видимости.
Время существования временного объекта заканчивается.
Программа заканчивается, глобальные или статические объекты продолжают существовать.
Деструктор явно вызываться с использованием полного имени функции деструктора.
Деструкторы могут свободно вызывать функции-члена класса и осуществлять доступ к данным членов класса.
Существуют два ограничения на использование деструкторов.
Вы не можете получить его адрес.
Производные классы не наследуют деструктор своего базового класса.
Порядок уничтожения
Когда объект выходит за пределы области или удаляется, последовательность событий при его полном уничтожении выглядит следующим образом:
Вызывается деструктор класса, и выполняется тело функции деструктора.
Деструкторы для объектов нестатических членов вызываются в порядке, обратном порядку их появления в объявлении класса. Необязательный список инициализации элементов, используемый при создании этих элементов, не влияет на порядок создания или уничтожения.
Деструкторы для невиртуальных базовых классов вызываются в обратную последовательность объявления.
Деструкторы для виртуальных базовых классов вызываются в порядке, обратном порядку их объявления.
Виртуальные базовые классы
Деструкторы для виртуальных базовых классов вызываются в порядке, обратном их указанию в направленном ациклическом графе (в глубину, слева направо, обход в обратном порядке). На следующем рисунке представлен граф наследования.
Граф наследования, показывающий виртуальные базовые классы
Ниже перечислены заголовки классов, представленных на рисунке.
Просмотрите левую часть графа, начиная с самой глубокой точки графа (в данном случае E ).
Просматривайте граф справа налево, пока не будут пройдены все узлы. Запомните имя текущего узла.
Пересмотрите предыдущий узел (вниз и вправо), чтобы определить, является ли рассматриваемый узел виртуальным базовым классом.
Если рассматриваемый узел является виртуальным базовым классом, просмотрите список, чтобы проверить, был ли он введен ранее. Если он не является виртуальным базовым классом, игнорируйте его.
Если рассматриваемого узла еще нет в списке, добавьте его вниз списка.
Просмотрите граф вверх и вдоль следующего пути вправо.
Перейдите к шагу 2.
Если путь последний путь вверх исчерпан, запомните имя текущего узла.
Перейдите к шагу 3.
Выполняйте этот процесс, пока нижний узел снова не станет текущим узлом.
Таким образом, для класса E порядок удаления будет следующим.
В ходе этого процесса создается упорядоченный список уникальных записей. Имя класса никогда не отображается дважды. После создания список просматривается в обратном порядке, и вызывается деструктор для каждого класса в списке от последнего к первому.
Порядок построения или удаления очень важен, когда конструкторы и деструкторы в одном классе полагаются на другой компонент, который создается первым или сохраняется дольше, например если деструктор A (на рисунке выше) полагается на то, что B будет по-прежнему присутствовать после выполнения кода, или наоборот.
Такие взаимозависимости между классами в графе наследования опасны, поскольку классы, наследуемые впоследствии, могут изменить крайний левый путь, тем самым изменив порядок построения и удаления.
Не являющиеся виртуальными базовыми классами
Деструкторы для невиртуальных базовых классов вызываются в порядке, в котором объявляются имена базовых классов. Рассмотрим следующее объявление класса.
Явные вызовы деструктора
Редко возникает необходимость в явном вызове деструктора. Однако может быть полезно выполнить удаление объектов, размещенных по абсолютным адресам. Обычно эти объекты выделяются с помощью определяемого пользователем new оператора, принимающего аргумент размещения. delete Оператор не может освободить эту память, так как она не выделена из бесплатного хранилища (Дополнительные сведения см. в разделе операторы new и DELETE). Вызов деструктора, однако, может выполнить соответствующую очистку. Для явного вызова деструктора для объекта ( s ) класса String воспользуйтесь одним из следующих операторов.
Нотация для явных вызовов деструкторов, показанная в предыдущем примере, может использоваться независимо от того, определяет ли тип деструктор. Это позволяет выполнять такие явные вызовы, не зная, определен ли деструктор для типа. Явный вызов деструктора, если ни один из них не определен, не имеет никакого эффекта.
Отказоустойчивость
Классу требуется деструктор, если он получает ресурс, и для безопасного управления ресурсом, вероятно, потребуется реализовать конструктор копии и назначение копирования.
Если эти специальные функции не определены пользователем, они неявно определяются компилятором. Неявно созданные конструкторы и операторы присваивания выполняют поверхностную почленном копию, которая почти наверняка неверно, если объект управляет ресурсом.
Явное определение деструктора, конструктора копирования или оператора присваивания копирования предотвращает неявное определение конструктора перемещения и оператора присваивания перемещения. В этом случае не удастся предоставить операции перемещения, если копирование занимает много ресурсов, но пропущенная возможность оптимизации.
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()
Резюме
Как видите, когда конструкторы и деструкторы используются вместе, ваши классы могут инициализироваться и очищаться после себя, без необходимости выполнения программистом какой-либо специальной работы! Это снижает вероятность ошибки и упрощает использование классов.
BestProg
Деструкторы. Определение деструктора. Общедоступные и приватные деструкторы. Примеры использования деструкторов. Отличия между конструкторами и деструкторами
Содержание
Поиск на других ресурсах:
1. Какое назначение деструктора в классе?
Деструктор – это обратная по отношению к конструктору функция.
Имя деструктора совпадает с именем класса, перед которым следует символ ‘
2. Пример использования общедоступного деструктора
Общий код модуля, в котором объявляется структура и класс.
Демонстрация использования данного класса в другом методе.
Да, можно. Такой деструктор называется приватным деструктором.
4. В каких случаях целесообразно объявлять приватные деструкторы?
Использование приватных деструкторов целесообразно в тех случаях, когда обычным пользователям запрещается освобождать память для прежде созданных объектов (уничтожать раньше созданные объекты).
5. Какие ограничения возникают при работе с объектами класса, если в классе объявлен приватный деструктор?
Если в классе объявлен приватный деструктор, то возникают следующие ограничения:
Это связано с тем, что такие объекты в дальнейшем невозможно будет уничтожить.
Например. Пусть задан класс, в котором объявлен приватный деструктор.
Если попробовать создать объект класса в другом программном коде
то компилятор выдаст ошибку
6. Может ли деструктор иметь параметры?
Деструктор не может иметь параметров.
7. Какие основные отличия между использованием конструкторов и деструкторов в классах?
При использовании в классе, между конструктором и деструктором можно определить следующие основные отличия:
Урок №120. Деструкторы
На этом уроке мы рассмотрим, что такое деструкторы в языке С++, зачем они нужны, как их использовать и нюансы, которые могут возникнуть при их использовании.
Деструкторы
Деструктор — это специальный тип метода класса, который выполняется при удалении объекта класса. В то время как конструкторы предназначены для инициализации класса, деструкторы предназначены для очистки памяти после него.
Когда объект автоматически выходит из области видимости или динамически выделенный объект явно удаляется с помощью ключевого слова delete, вызывается деструктор класса (если он существует) для выполнения необходимой очистки до того, как объект будет удален из памяти. Для простых классов (тех, которые только инициализируют значения обычных переменных-членов) деструктор не нужен, так как C++ автоматически выполнит очистку самостоятельно.
Однако, если объект класса содержит любые ресурсы (например, динамически выделенную память или файл/базу данных), или, если вам необходимо выполнить какие-либо действия до того, как объект будет уничтожен, деструктор является идеальным решением, поскольку он производит последние действия с объектом перед его окончательным уничтожением.
Имена деструкторов
Так же, как и конструкторы, деструкторы имеют свои правила, которые касаются их имен:
деструктор должен иметь то же имя, что и класс, со знаком тильда (
деструктор не может принимать аргументы;
деструктор не имеет типа возврата.
Из второго правила вытекает еще одно правило: для каждого класса может существовать только один деструктор, так как нет возможности перегрузить деструкторы, как функции, и отличаться друг от друга аргументами они не могут.
Пример использования деструктора на практике
Рассмотрим простой класс с деструктором:
Massiv() вызывается тоже здесь
Результат выполнения программы:
The value of element 7 is 8
В первой строке функции main() мы создаем новый объект класса Massiv с именем arr и передаем длину ( length ) 15. Это приводит к вызову конструктора, который динамически выделяет память для массива класса ( m_array ). Мы должны здесь использовать динамическое выделение, поскольку на момент компиляции мы не знаем длину массива (это значение нам передает caller).
В конце функции main() объект arr выходит из области видимости. Это приводит к вызову деструктора
Massiv() и к удалению массива, который мы выделили ранее в конструкторе!
Выполнение конструкторов и деструкторов
Как мы уже знаем, конструктор вызывается при создании объекта, а деструктор — при его уничтожении. В следующем примере мы будем использовать стейтменты с cout внутри конструктора и деструктора для отображения их времени выполнения:
Результат выполнения программы:
Constructing Another 1
1
Constructing Another 2
2
Destructing Another 2
Destructing Another 1
Идиома программирования RAII
Идиома RAII (англ. «Resource Acquisition Is Initialization» = «Получение ресурсов есть инициализация») — это идиома объектно-ориентированного программирования, при которой использование ресурсов привязывается к времени жизни объектов с автоматической продолжительностью жизни. В языке C++ идиома RAII реализуется через классы с конструкторами и деструкторами. Ресурс (например, память, файл или база данных) обычно приобретается в конструкторе объекта (хотя этот ресурс может быть получен и после создания объекта, если в этом есть смысл). Затем этот ресурс можно использовать, пока объект жив. Ресурс освобождается в деструкторе при уничтожении объекта. Основным преимуществом RAII является то, что это помогает предотвратить утечку ресурсов (например, памяти, которая не была освобождена), так как все объекты, содержащие ресурсы, автоматически очищаются.
В рамках идиомы программирования RAII объекты, располагающие ресурсами, не должны быть динамически выделенными, так как деструкторы вызываются только при уничтожении объектов. Для объектов, выделенных из стека, это происходит автоматически, когда объект выходит из области видимости, поэтому нет необходимости беспокоиться о том, что ресурс в конечном итоге не будет очищен. Однако за очистку динамически выделенных объектов, которые выделяются из кучи, уже пользователь несет ответственность: если он забыл её выполнить, деструктор вызываться не будет, и память как для объекта класса, так и для управляемого ресурса будет потеряна — произойдет утечка памяти!
Класс Massiv из программы, приведенной в начале этого урока, является примером класса, который реализует принципы RAII: выделение в конструкторе, освобождение в деструкторе. std::string и std::vector — это примеры классов из Стандартной библиотеки С++, которые следуют принципам RAII: динамическая память выделяется при инициализации и автоматически освобождается при уничтожении.
Правило: Используйте идиому программирования RAII и не выделяйте объекты вашего класса динамически.
Предупреждение о функции exit()
Если вы используете функцию exit(), то ваша программа завершится, и никакие деструкторы не будут вызваны. Будьте осторожны, если в таком случае вы полагаетесь на свои деструкторы для выполнения необходимой работы по очистке (например, перед тем, как выйти, вы записываете что-нибудь в лог-файл или в базу данных).
Заключение
Используя конструкторы и деструкторы, ваши классы могут выполнять инициализацию и очистку после себя автоматически без вашего участия! Это уменьшает вероятность возникновения ошибок и упрощает процесс использования классов.
Поделиться в социальных сетях:
Урок №119. Делегирующие конструкторы
Комментариев: 14
Не совсем понял фразу в тексте: «В рамках идиомы программирования RAII объекты, располагающие ресурсами, не должны быть динамически выделенными, так как деструкторы вызываются только при уничтожении объектов». Ведь деструкторы нужны в основном только при использовании динамической памяти, а тут написано, что «объекты не должны быть динамически выделенными». Как-то я запутался. Даже GOOGLE не помог.
Кто бы мне объяснил, я бы был очень благодарен.
Если объект создается в автоматической области памяти (напр. в функции), то при выходе из этой области он будет уничтожен деструктором автоматически, без вашего участия. Если же вы создаете объекты в динамической памяти (используя new), то освобождать ее вы должны сами операцией delete (это должно быть отражено в деструкторе вами, те дб написан нужный код). Почитайте «Язык программирования C++. Лекции и упражнения» Стивена Прата
6-е издание, глава 12 — там все есть.
Коротко, емко, толково. Спасибо. Хотя все это и знал, но не могу не оставить положительный отзыв за грамотное и сжатое изложение.
Конструкторы и деструкторы
Конструкторы
Конструктор — функция, предназначенная для инициализации объектов класса. Рассмотрим класс date :
Если конструктор требует аргументы, их следует указать:
Если необходимо обеспечить несколько способов инициализации объектов класса, задается несколько конструкторов:
Конструкторы подчиняются тем же правилам относительно типов параметров, что и перегруженные функции. Если конструкторы существенно различаются по типам своих параметров, то компилятор при каждом использовании может выбрать правильный:
Одним из способов сократить количество перегруженных функций (в том числе и конструкторов) является использование значений по умолчанию.
Конструктор по умолчанию
При создании объекта вызывается конструктор, за исключением случая, когда объект создается как копия другого объекта этого же класса, например:
Однако имеются случаи, в которых создание объекта без вызова конструктора осуществляется неявно:
Во всех этих случаях транслятор не вызывает конструктора для вновь создаваемого объекта:
Вместо этого в них копируется содержимое объекта-источника:
Конструктор копии
Как правило, при создании нового объекта на базе уже существующего происходит поверхностное копирование, то есть копируются те данные, которые содержит объект-источник. При этом если в объекте-источнике имеются указатели на динамические переменные и массивы, или ссылки, то создание копии объекта требует обязательного дублирования этих объектов во вновь создаваемом объекте. С этой целью вводится конструктор копии, который автоматически вызывается во всех перечисленных случаях. Он имеет единственный параметр — ссылку на объект-источник:
Деструкторы
Определяемый пользователем класс имеет конструктор, который обеспечивает надлежащую инициализацию. Для многих типов также требуется обратное действие. Деструктор обеспечивает соответствующую очистку объектов указанного типа. Имя деструктора представляет собой имя класса с предшествующим ему знаком «тильда»
. Так, для класса X деструктор будет иметь имя
Поля, имеющие тип класса
Конструкторы членов класса всегда выполняются до конструктора класса, в котором эти члены описаны. Порядок выполнения конструкторов для членов класса определяется порядком объявления членов класса. Если конструктору члена класса требуются аргументы, этот член с нужными аргументами указывается в списке инициализации. Деструкторы вызываются в обратном порядке.