Основы программирования на С++ для начинающих

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

Когда новички изучают программирование, первым делом, при рассмотрении новой темы, возникает вопрос – для чего необходима та или иная “вещь” о которой сейчас предстоит узнать. Ответим сразу на этот вопрос: “Зачем нужен конструктор копирования?”.

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

  • при передаче объекта класса в функцию, как параметра по значению (а не по ссылке);
  • при возвращении из функции объекта класса, как результата её работы;
  • при инициализации  одного объекта класса другим объектом этого класса.

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

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

Использование конструктора копирования – прекрасный способ обойти эти ошибки и проблемы. Он создаст “реальную” копию объекта, которая будет иметь личную область динамической памяти.

Конструктор копирования синтаксически выглядит так:

Ниже разберём несложный, но очень показательный пример. В нём будут рассмотрены все 3 случая в которых желательно применять конструктор копирования. Будет создан класс, содержащий конструктор без параметров, конструктор копирования и деструктор.

Чтобы пример был не слишком громоздким, конструкторы и деструктор будут выводить на экран сообщения типа “Сработал конструктор”, “Сработал дектруктор”…  Выделять и освобождать память не будем.

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

Пример:

Конструктор без параметров будет вызываться во время создания новых объектов класса. Конструктор копирования  – во время создания копий объекта. Деструктор срабатывает при удалении и реального объекта и его копии. В теле функций все описано подробно и не требует дополнительных комментариев.

Запустив программу увидим в консоли следующее:

конструктор копирования в с++,  конструктор копии c++,  программирование на с++ с нуля

Посмотрим что программа выдала в консоль. Блок 1 –  во время создания нового объекта, сработал конструктор без параметров. В блоке 2  мы разместили функцию  showFunc(). Во время передачи в неё “объекта-параметра” по значению, сработал конструктор копирования и создалась “реальная” копия объекта класса OneClass.

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

В блоке 3 размещена функция returnObjectFunc(). Так как в её теле прописано создание нового объекта класса OneClass – сначала сработал конструктор без параметров. Далее выполняется код функции и во время возврата объекта в главную функцию main, сработал конструктор копирования.  В конце, как и должно быть, деструктор отработал дважды: для объекта и для его реальной копии.

В четвертом блоке, во время объявления и инициализации нового объекта object2, сработал конструктор копирования. При завершении работы программы деструктор сработал для копии объекта из четвертого блока и для объекта object1 из первого блока.

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

конструктор копирования в с++,  конструктор копии c++, программирование на с++ с нуля

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

Очень рекомендую прочесть тему Конструктор копирования в книге Стивена Прата “Язык программирования С++. Лекции и упражнения. 6-е издание.” Она раскрыта намного глубже и включает все основные нюансы использования конструктора копирования. Подробно рассмотрена операция присваивания .

6 thoughts on “Конструктор копирования в С++

  1. А почему в коде определен, неиспользуемый указатель?
    int *ptr; // какой-то указатель

    1. Потому что хоть какая-то переменная, член класса, должна быть определена в классе?
      Если вам не нравится указатель, определите переменную типа int.

  2. В 3-м блоке конструктор копирования не вызывается, соответственно и 2-го деструктора нет. Это для компиляторов MinGW, CLang(онлайн компилятор ). Для microsoft vc++ все работает, как и в примере.

    1. Потому что там действительно нет объекта, в который нужно возвращать результат.
      Нужно бы записать как-то так:

      OneClass object2( returnObjectFunc() );

      Или так:

      OneClass object2 = returnObjectFunc();

Добавить комментарий для Yuriy Отменить ответ

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