Конструкторы и дестркутор по умолчанию в С++
Программирование › Программирование на С++ › Учебные материалы по С++ › Конструкторы и дестркутор по умолчанию в С++
Помечено: cplusplus, деструктор, конструктор, конструктор копирования
В этой теме 2 ответа, 2 участника, последнее обновление 2 года/лет, 10 мес. назад.
- АвторСообщения
- 20.04.2016 в 03:45 #2711@questioner
Здравствуйте. Говорят, что в С++ компилятор автоматически генерирует конструктор без параметров, конструктор копирования и дестркутор. Зачем тогда их иногда пишут вручную?
- 21.04.2016 в 09:32 #2716@admin
Компилятор автоматически генерирует:
- конструктор копирования, выполняющий копирование каждого нестатического поля (члена данных);
- оператор присваивания, выполняющий ту же операцию, что и конструктор копирования;
- деструктор, освобождающий память из под объекта. Только если в базовом классе есть виртуальный деструктор, то сгенерированный тоже будет виртуальным.
Понятно, что если ваш класс не наследует класс с виртуальным деструктором, но при этом вы допускаете его полиморфное использование — вам надо явно (руками) описывать этот деструктор. Кроме того, надеяться на деструктор, созданный неявно нельзя если объект внутри использует динамическое выделение памяти:
class LeakClass { char *s; public: LeakClass() { s = new char[255]; } };
Деструктор освободит память, занимаемую указателем (пусть 4 байта), но не вызовет операторdelete[]
для строки из 255 байт.Аналогичная проблема возникнет конструкторе копирования и операторе присваивания:
class LeakClass { char *s; public: LeakClass() { s = new char[255]; } ~LeakClass() { delete[] s; } }; // ... { LeakClass a, b; // вызов конструктора LeakClass c(a); // вызов конструктора копирования b = a; // вызов оператора присваивания } // объекты выходят из области видимости, вызываются деструкторы
В этом примере при создании объектов
a
иb
будет динамически выделена память, однако при создании объектаc
будет лишь скопирован указатель, т.е. объектc
будет работать с памятью, выделенной в объектеa
. Аналогично присваивание указателя будет выполнено оператором присваивания. В коде есть множество проблем, которые иногда очень трудно найти:- внутри у нескольких объектов находится указатель на одну и ту же область памяти, которая освобождается в деструкторе. Если один из объектов уничтожается, то у остальных оказывается указатель на уже освобожденную память. Найти ошибку иногда очень сложно, т.к. при выполнении
delete[]
содержимое памяти не изменится, она просто будет помечена как свободная — проблемы начнутся только когда другой объект получит эту же область памяти и перезапишет ее; - объекты будут освобождать область памяти, которая уже была освобождена;
- при выполнении присваивания у объекта, стоящего слева от оператора будет происходить утечка памяти, т.к. указатель получит новое значение, но по старому указателю в конструкторе была выделена память.
Решить проблему можно написав свои собственные реализации оператора присваивания и конструктора копирования, однако в большинстве случаев проблема решается использованием умных указателей. В рассмотренном примере проблему можно решить применением объекта типа
string
вместо массива символов.Компилятор создаст эти функции только если они будут использоваться, т.к. в С++ вы не платите за то, что не используете. Если в вашей программе не применяется оператор присваивания с объектами вашего класса — то и метод сгенерирован не будет. Однако нужно быть очень внимательным, т.к. конструктор копирования вызывается, например, при передаче объекта по значению.
Кроме того, если вы не напишите в своем коде вообще никакого конструктора — компилятор создаст конструктор по умолчанию (работающий без параметров).
- 21.04.2016 в 13:14 #2717@admin
Запустим наши примеры.
int main() { LeakClass a, b; }
Программа отрабатывает без ошибок, но как только добавим вызов конструктора копирования (который создан неявно) — получим ошибку во время выполнения (память по указателю очищается дважды):
LeakClass c(a);
- АвторСообщения
Для ответа в этой теме необходимо авторизоваться.