Деструктор. Конструктор с параметрами. Первое погружение

Эта тема предназначена для тех, кто идёт по списку тем сайта. Если вы зашли сюда из поиска, то полезного будет мало.
Работа конструкторов и деструкторов тесно связана. Работа с конструкторами обычно выглядит яснее, чем работа с деструкторами, но большое количество конструкторов и наличие так называемых "временных объектов" осложняют осмысление происходящего. В зависимости от того, как объявляется объект, в большинстве случаев можно правильно предсказать, какой будет вызван конструктор класса. Но не все случаи однозначны. В идеале вам под рукой иметь несколько разных компиляторов, чтобы посмотреть эффект работы показанного далее кода.

Смысл листинга #1 только показать, что деструкторы выполняются в обратном порядке объявленным объектам. Это действует всегда так, потому что объявленные нами переменные-объекты локальные, не static и не указательного с выделенной им памятью характера, такие располагаются на стеке. Расположение на стеке обозначает, что кто последним создан, тот первым будет уничтожен. Поэтому при выполнении программы вы видите, что girl как бы обернулась boy. Вам важно понять порядок: разрушение сейчас происходит в обратном созданию порядке, потому что переменные-объекты нашего кода запоминаются в стеке. Объяснить, что такое стек, мне немного проблематично. Просто пока что запомните, что стек — это такой механизм, который использует пришедшие в себя элементы с самого последнего отданного ему, стремясь к самому первому отданному ему. При выполнении нашей программы деструктор демонстрирует такую организацию процесса.

В листинге #2 порядок работы отличен от листинга #1. Это связано с тем, что срок существования автоматических переменных, таких как наши boy и girl, истекает, когда выполнение программы покидает блок, содержащий их определения. Мы объявили переменные-объекты, определились с их значениями, они зАжили, но блок, ограничивший их мир, обозначил им границы жизни. В первом блоке истёк срок жизни первой переменной-объекта, поскольку других переменных-объектов внутри блока не было, то и конструктор и деструктор выполнились для того единственного объекта, потом пришла очередь второй переменной-объекта, и всё произошло точно так же. Вам надо понять это отличие, чтобы было легче ориентироваться с вопросом: когда срабатывает деструктор.
О деструкторах поговоирили, поразмышляли, надеюсь, что ещё и понять сумели. Теперь поговорим о конструкторах. Обо всех не будем, их многовато, поговорим просто об обычном конструкторе с параметрами. То, что он может быть конвертирующим, сейчас пока что значения иметь не будет. И так и эдак такой конструктор принимает в свои параметры передаваемые туда аргументы извне. Посмотрим код:

В листинге #3 используется два способа для инициации одного и того же вида конструктора. В нашем случае мы отдаём в объект класса аргументы, срабатывает конструктор с параметрами, который мы описали вручную внутри класса. Несмотря на то, что оба варианта инициации одного и того же конструктора достаточно сильно похожи, второй в разных компиляторах может работать по-разному. Для тех, кому сложно понять слово "инициировать", это слово обозначает "спровоцировать запуск", просто его вы будете встречать достаточно часто, поэтому выбрано оно.
Второй способ инициации конструктора с параметрами выполняется по простой схеме: обозначается тип, которому скармливают аргументы, которые должен будет пережевать конструктор. Эта форма напоминает форму явного приведения типов, когда тип заворачивается в круглые скобки, а за ним пишутся переменные, тут немного наоборот. Вот в одном случае получается приведение типов, а если кормить типу параметры, то запуск конструктора. Так вот, второй способ инициации конструктора с параметрами отличается и тем, что в разных компиляторах может получаться разный эффект. В некоторых компиляторах будет срабатывать деструктор временного объекта, поэтому можно увидеть как будто бы лишнее сообщение.

  • В данном контексте может быть создан временный объект, но в угоду эффективности современные компиляторы применяют оптимизацию copy-elision, и не создают временного объекта. Начиная с C++17 такая оптимизация является обязательной.
Пример листинга #3 Приведён, чтобы вы знали, что в старых версиях С++ можно встретить случай с выполнением деструктора от временного объекта, если бы это случилось, то на экран бы вывелось 3 строки:

boy constructed
girl constructed
girl destroyed

girl destroyed
boy destroyed
          

Тема copy ellision выходит за рамки статьи. Если хотите, поинтересуйтесь в книгах, в гугле.

Вернёмся к листингу #3. Почему сработало присваивание? Потому что к объектам одного и того же класса допустима операция присваивания, один объект будет скопирован в другой. По той причине, что объекты одного класса можно присваивать друг в друга, конструктор класса можно использовать не только для инициализации, но и для присваивания объекта в объект.


В отличие от листинга #3, где присваивание значения в объект происходит в момент объявления, т. е. где происходит инициализация объекта значением, в листинге #4 объект, в который присваивается значение, существует уже некоторое время. Если в старых версиях компиляторов при инициализации объекта с помощью конструктора с параметрами могло или происходить создание временного или не происходить, то в случае обычного присваивания такого вида, независимо от компилятора, временный объект создаётся всегда. Поскольку в случае инициализации раньше временный объект мог как создаваться, так и не создаваться, а в современных при инициализации не создаётся вообще (с с++17 по закону), а при присваивании показанного вида создаётся временный объект всегда, то предпочтение при возможности выбора между инициализацией значением и просто присваиванием отдавать нужно инициализации, а не присваиванию.


Использованные материалы:

Язык программирования C++. Лекции и упражнения. 6-е изд (Стивен Прата)

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

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

Поиск

 
     

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

https://www.litres.ru/denis-kolisnichenko/rukovodstvo-po-komandam-i-shell-programmirovaniu-v-linux/?lfrom=15589587
Яндекс.Метрика