Знакомимся с деструктором на примере создания объекта-массива

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

Обычные объекты, под которые не выделялось памяти, живут в своём блоке кода и, если они не static, не под влиянием new, а самые обычные, то вместе с завершением блока кода завершают своё существование. В листинге #1 два объявления завёрнуты каждый в свой блок, внутри одного живёт одно, внутри другого другое, а после подхода компилятора к завершающей блок части, включается деструктор.
Возможно, вам сложно понять, зачем нужны деструкторы. В С++ программисту позволено работать с памятью. Когда программист берёт управление памятью в свои руки, то для возможности существования объекта в памяти компьютера выделяется память, которую потом нужно не забывать очищать. Это хорошо знакомо тем, кто выделял память под массивы.

Когда код большой, тогда легко не уследить за delete, не написать в коде, чем допустить утечку памяти. Деструкторы помогают частично избавиться от уделения особого внимания выделению и зачистке. И выделение памяти и очистка памяти заворачиваются в один объект, порождаемый классом, и потом такой порождённый объект ведёт себя как если бы он был обычной переменной. Т. е. если внутри класса есть какая-то переменная, требующая выделения памяти, и в такой класс в конструктор запрограммировать выделение памяти, а в деструктор высвобождение, то порождаемый от класса объект будет самостоятельно выделять память той внутренней классу переменной (при объявлении объекта) и выполнять высвобождение памяти (при уничтожении объекта).
Классический пример: использование указателя в качестве массива. Когда требуется массив, число вмещаемых элементов которого задаётся при выполнении программы, а не во время компиляции, в стиле С++, тогда требуется использование пары new и []delete). Если эту пару завернуть в класс, выделяющую часть в конструктор, а разрушающую в деструктор, то станет легко создавать массив через объект класса, следить за выделением и высвобождением памяти не придётся.

  • Деструктор по своей форме очень похож на конструктор, единственно отличие в синтаксисе — добавление значка тильды.
В листинге #2 мы фактически получили эквивалент массива, обернув составляющие, воспроизводящие массив, классом. Теперь можно создавать много объектов и не заботиться о выделении и очистке памяти. Эти заботы теперь берёт на себя объект, который выполняет роль нашего массива. Добавим в класс информационную часть. Будем заполнять массив и выводить данные массива на экран. Для этого встроим в класс два метода (метод заполнения массива и метод вывода массива на экран).

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

Единственное, нужно один раз описать, как выделять и как высвобождать память, дальше всё резко упрощается. Основное предназначение деструктора помогать разрушать объект, которому помогали конструироваться. В отличие от конструкторов, видов которых много, деструктор всего один. В приведённом примере у меня в конструкторе (который по умолчанию) указатель принудительно перенаправляется в ноль. Делается это для того, чтобы избежать []delete к указателю, не удостоившемуся выделения памяти. Не факт, что внутренняя для класса указательная переменная, которой памяти не выделяется, будет указывать на объект, память которому выделялась.

Чтобы не получилась ситуация, как показана в листинге #a1, нужно delete использовать только в паре со new, исключением являетя применение delete к нулю. То, что пришлось это использовать — это издержка того, что если мы описываем любой конструктор класса, то обязательно описывать и конструктор класса по умолчанию. Этот конструктор по умолчанию мог бы нам помешать. Ведь мы привыкли объявлять переменные без использования круглых скобок, но если так объявлять объект класса, то запускается конструктор класса по умолчанию, а когда объект прекращает своё существование, тогда запускается деструктор. Коли нами в конструкторе по умолчанию не выделялось памяти, а в деструкторе обязательно сработает delete []ptr, то delete []ptr применится к учатку памяти, к которому ему может быть нельзя. Только из-за этого указательная переменная в конструкторе по умолчанию направлялась в ноль. Можно было выделить ей памяти, но выделение памяти операция долгая, поэтому вариант с перенаправлением в ноль предпочтительней.
Иногда нежелателен запуск конструктора по умолчанию. Например, в нашем случае могло быть желательно только создание массива с явным указанием элементов. Коли нам обязательно добавлять конструктор умолчания в класс, если мы внедряем в клас другие виды конструкторов, но срабатывание конструктора умолчания нам вообще не нужно и даже мешает, мы можем спрятать этот конструктор в секцию private

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

К сожалению, не всё в моих силах. Вам лучше всего поиграть с использованием объекта и подсматриваем данных о его жизни (конструировании и уничтожении). Трудность может возникнуть именно с конструкторами, потому что в зависимости от ситуации может вызываться или один, или второй, или третий вид конструктора. Но какой из конструкторов будет вызван, можно судить по коду. До этого момента на сайте рассматривались конструктор по умолчанию (вызывается, если в месте объявления объекта объекту скобок не давать), конструктор копирования (вызывается, если при объявлении уходящим аргументом или при присваивании оказывается объект того же класса, что и объявляемый), конвертирующий конструктор (конструктор с одним или более параметрами), просто конструктор с параметрами (если запрещен конвертирующий).
Резюмируем:

  • Обычно деструктор используется для "очистки", когда объект больше не нужен.
  • Деструктор противоположность конструктору.
  • Деструктор объявляется подобно конструктору умолчания, но с приставлением значка тильды ~.
  • Деструктор не разделяется на виды, в отличие от конструкторов, и не может иметь параметров.
  • Всегда (если не заставлять принудительно) деструктор вызывается автоматически, когда объект прекращает своё существование.

Один комментарий на «“Знакомимся с деструктором на примере создания объекта-массива”»

  1. Александр:

    Спасибо за ваш труд!!!

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

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

Поиск

 
     

Случайная книга в электронном формате

https://www.litres.ru/d-uittaker/kak-testiruut-v-google/?lfrom=15589587

Последние комментарии

Яндекс.Метрика