Глубокое погружение в деструкторы
Часть раздела Объектно-ориентированное программирование путешествия по C++ на Coddy — урок 24 из 104.
Деструктор — это специальная функция-член, которая выполняется автоматически при уничтожении объекта. Его основная задача заключается в освобождении ресурсов, которые объект получил за время своего существования, таких как динамически выделенная память, дескрипторы файлов или сетевые соединения.
Деструктор имеет то же имя, что и класс, с префиксом в виде тильды ~. Он не принимает параметров и не имеет возвращаемого типа:
class FileHandler {
std::string filename;
int* buffer;
public:
FileHandler(std::string name, size_t size)
: filename(name), buffer(new int[size]) {
std::cout << "Opening " << filename << "\n";
}
~FileHandler() {
delete[] buffer;
std::cout << "Closing " << filename << "\n";
}
};Деструкторы вызываются автоматически в следующих ситуациях:
- Объекты в стеке выходят из области видимости
deleteвызывается для объекта, выделенного в куче- Время жизни временного объекта заканчивается
void example() {
FileHandler f1("data.txt", 100); // Вызван конструктор
FileHandler* f2 = new FileHandler("log.txt", 50);
delete f2; // Вызван деструктор для f2
} // Вызван деструктор для f1 (выходит из области видимости)В отличие от конструкторов, класс может иметь только один деструктор. Его нельзя перегружать.
Если вы не определите его, компилятор создаст деструктор по умолчанию, который не делает ничего особенного — он просто уничтожает каждый член класса. Для классов, управляющих ресурсами, вы должны написать свой собственный деструктор, чтобы предотвратить утечки памяти.
Задание
ЛегкоДавайте создадим менеджер сессий, который отслеживает активные сессии пользователей и демонстрирует, как деструкторы автоматически очищают ресурсы при уничтожении объектов — независимо от того, выходят ли они из области видимости или удаляются явно.
Вы создадите два файла для организации вашего кода:
Session.h: Определите классSession, который представляет активную сессию пользователя с динамически выделенными данными. Ваш класс должен иметь:- Приватные члены:
username(string),sessionId(int) и указатель на целочисленный массив с именемactivityLog, который отслеживает действия пользователя, а такжеlogSizeдля размера массива. - Конструктор, который принимает имя пользователя, ID сессии и размер лога. Он должен выделять массив лога активности в куче, инициализировать все элементы значением 0 и выводить
"Session <sessionId> started for <username>". - Деструктор, который освобождает выделенную память и выводит
"Session <sessionId> ended for <username>". - Метод
logActivity(int activityCode), который сохраняет код активности в следующую доступную ячейку (отслеживайте текущую позицию внутри класса). - Метод
getActivityCount(), который возвращает количество зарегистрированных активностей. - Метод
getUsername(), который возвращает имя пользователя.
- Приватные члены:
main.cpp: Продемонстрируйте поведение деструктора в различных сценариях. Считайте имя пользователя и размер лога из входных данных (каждое с новой строки), затем:- Создайте блок области видимости, используя фигурные скобки
{ }, и внутри него создайте объектSessionв стеке с введенным именем пользователя, ID сессии101и введенным размером лога. Запишите две активности с кодами1и2, затем выведите"Stack session activities: <count>". Когда блок закончится, деструктор должен запуститься автоматически. - После блока выведите
"Stack session destroyed". - Создайте объект
Sessionв куче, используяnew, с именем пользователя"Guest", ID сессии202и размером лога3. Запишите одну активность с кодом5, выведите"Heap session activities: <count>", а затем явно удалите его с помощьюdelete. - После удаления выведите
"Heap session destroyed".
- Создайте блок области видимости, используя фигурные скобки
Эта задача показывает два основных способа вызова деструкторов: автоматически, когда объекты стека выходят из области видимости, и вручную, когда вы удаляете объекты в куче. Оба пути должны правильно освобождать динамически выделенный лог активности для предотвращения утечек памяти.
Включите ваш заголовочный файл в main.cpp, используя #include "Session.h".
Шпаргалка
Деструктор — это специальная функция-член, которая запускается автоматически при уничтожении объекта. Он освобождает ресурсы, такие как динамически выделенная память, дескрипторы файлов или сетевые соединения.
Деструктор имеет то же имя, что и класс, с префиксом в виде тильды ~. Он не принимает параметров и не имеет возвращаемого типа:
class FileHandler {
std::string filename;
int* buffer;
public:
FileHandler(std::string name, size_t size)
: filename(name), buffer(new int[size]) {
std::cout << "Opening " << filename << "\n";
}
~FileHandler() {
delete[] buffer;
std::cout << "Closing " << filename << "\n";
}
};Деструкторы вызываются автоматически, когда:
- Объекты в стеке выходят из области видимости
deleteвызывается для объекта, выделенного в куче- Заканчивается время жизни временного объекта
void example() {
FileHandler f1("data.txt", 100); // Вызывается конструктор
FileHandler* f2 = new FileHandler("log.txt", 50);
delete f2; // Вызывается деструктор для f2
} // Вызывается деструктор для f1 (выход из области видимости)У класса может быть только один деструктор (перегрузка невозможна). Если вы его не определите, компилятор создаст деструктор по умолчанию. Для классов, управляющих ресурсами, необходимо написать собственный деструктор, чтобы предотвратить утечки памяти.
Попробуйте сами
#include <iostream>
#include <string>
#include "Session.h"
using namespace std;
int main() {
// Чтение входных данных
string username;
int logSize;
getline(cin, username);
cin >> logSize;
// TODO: Создайте блок области видимости с фигурными скобками { }
// Внутри блока:
// - Создайте объект Session в стеке с введенным username, ID сессии 101 и введенным размером лога
// - Запишите два действия с кодами 1 и 2
// - Выведите "Stack session activities: <count>"
// Когда блок закончится, деструктор запустится автоматически
// TODO: После блока выведите "Stack session destroyed"
// TODO: Создайте объект Session в куче, используя new
// - Username: "Guest", ID сессии: 202, размер лога: 3
// - Запишите одно действие с кодом 5
// - Выведите "Heap session activities: <count>"
// - Удалите сессию
// TODO: После удаления выведите "Heap session destroyed"
return 0;
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Основы ООП
Внешние файлыСборка и компиляция C++Заголовочные файлы и файлы исходного кодаПространства имен и область видимостиВведение в ООП на C++Классы и объектыУказатель 'this'Методы (функции-члены)Атрибуты (члены данных)Основы конструкторов и деструкторовИтоги — Простой калькулятор4Свойства классов
Члены экземпляра против статическихГеттеры и сеттерыКонстантные функции-членыКлючевое слово mutableСтатические методы и переменныеДружественные функции и классыИтоги — Менеджер банковских счетов7Наследование
Основы наследованияУровни доступа при наследованииПорядок вызова конструкторов и деструкторовПереопределение методовВиртуальные функции и VTableМножественное наследованиеВиртуальное наследованиеИтоги — Иерархия сотрудников10Обзор STL
Обзор и философия STLКонтейнеры STLИтераторыАлгоритмы STLФункторы и лямбда-выраженияИтоги: частота слов13Паттерны проектирования. Часть 1
Введение в паттерны проектированияПаттерн SingletonFactory и Abstract FactoryПаттерн BuilderПаттерн ObserverПаттерн Strategy2Управление памятью
Стек и кучаУказатели и ссылкиДинамическая память (new/delete)Умные указатели в C++RAII в C++Итоги — Менеджер динамического массива5Инкапсуляция
Спецификаторы доступа в C++Спецификаторы доступа: подробный разборСокрытие данныхStruct против ClassВложенные и внутренние классыИтоги — Система учета студентов8Полиморфизм
Полиморфизм компиляции и времени выполненияПерегрузка функцийВиртуальные функции: повторениеЧистые виртуальные функцииАбстрактные классыПроектирование интерфейсов на C++Dynamic Casting и RTTIИтоги: Калькулятор фигур11Продвинутые концепции ООП
Композиция против наследованияМиксины через CRTPИдиома PimplСтирание типовEnum Classes и строгая типизацияОбработка исключений в ООППользовательские иерархии исключений14Паттерны проектирования. Часть 2
Паттерн КомандаПаттерн АдаптерПаттерн ДекораторПаттерн Шаблонный методПаттерн СостояниеПаттерн КомпоновщикRAII как паттерн3Конструкторы и деструкторы
Конструктор по умолчаниюПараметризованный конструкторКонструктор копированияКонструктор перемещенияСписки инициализации конструктораДелегирующие конструкторыГлубокое погружение в деструкторыПравило трех / пяти / нуляПовторение — класс String6Перегрузка операторов
Введение в перегрузку операторовПерегрузка арифметических операторовПерегрузка операторов сравненияОператоры потоковПерегрузка оператора присваиванияПерегрузка операторов [] и ()Операторы преобразования типовИтоги — класс Matrix9Шаблоны
Шаблоны функцийШаблоны классовСпециализация шаблоновВариативные шаблоныОсновы SFINAE и Type TraitsИтоги — Обобщенный контейнер