Глубокое погружение в деструкторы
Часть раздела Объектно-ориентированное программирование путешествия по C++ на Coddy. Урок 24 из 104.
destructor — это специальная функция-член, которая автоматически запускается, когда объект уничтожается. Её основная задача — освобождать ресурсы, приобретённые объектом за время его существования, например динамически выделенную память, дескрипторы файлов или сетевые подключения.
destructor имеет то же имя, что и class, с префиксом в виде тильды ~. Он не принимает параметров и не имеет возвращаемого типа:
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";
}
};Деструкторы called автоматически в следующих ситуациях:
- Объекты в стеке выходят из области видимости
- Для объекта, выделенного в куче, вызывается
delete - Время жизни временного объекта заканчивается
void example() {
FileHandler f1("data.txt", 100); // Вызван конструктор
FileHandler* f2 = new FileHandler("log.txt", 50);
delete f2; // Вызван деструктор для f2
} // Вызван деструктор для f1 (выходит из области видимости)В отличие от конструкторов, у class может быть только один destructor. Его нельзя перегружать.
Если вы не определите его, компилятор сгенерирует destructor по умолчанию, который не делает ничего особенного — он просто уничтожает каждый член. Для классов, управляющих ресурсами, вы должны написать собственный destructor, чтобы предотвратить утечки памяти.
Задание
ЛегкоДавайте создадим менеджер сессий, который отслеживает активные пользовательские сессии и демонстрирует, как деструкторы автоматически освобождают ресурсы при уничтожении объектов — независимо от того, выходят ли они из области видимости или удаляются явно.
Вы создадите два файла, чтобы организовать код:
Session.h: определитеSessionclass, представляющий активную пользовательскую сессию с Dynamically выделенными данными. У вашего class должны быть:- Закрытые члены:
username(строка),sessionId(целое число) и указатель на целочисленный массив под названиемactivityLog, который отслеживает действия пользователя, а такжеlogSizeдля хранения размера массива - Конструктор, принимающий имя пользователя, идентификатор сессии и размер журнала. Он должен выделить массив журнала действий в куче, инициализировать all элементы значением 0 и вывести
"Session <sessionId> started for <username>" - Деструктор, который освобождает выделенную память и выводит
"Session <sessionId> ended for <username>" - Метод
logActivity(int activityCode), сохраняющий код действия в следующей available позиции (текущая позиция отслеживается внутри объекта) - Метод
getActivityCount(), возвращающий количество зарегистрированных действий - Метод
getUsername(), возвращающий имя пользователя
- Закрытые члены:
main.cpp: продемонстрируйте работу деструктора в разных сценариях. Считайте имя пользователя и размер журнала из входных данных (каждое значение находится в отдельной строке), затем:- Создайте блок области видимости с помощью фигурных скобок
{ }и внутри него создайте размещённый в стекеSessionс введённым именем пользователя, идентификатором сессии101и введённым размером журнала. Зарегистрируйте два действия с кодами1и2, затем выведите"Stack session activities: <count>". Когда блок ends, деструктор должен запуститься automatically. - После блока выведите
"Stack session destroyed" - Создайте размещённый в куче
Sessionс помощьюnew, используя имя пользователя"Guest", идентификатор сессии202и размер журнала3. Зарегистрируйте одно действие с кодом5, выведите"Heap session activities: <count>", а затем явно выполнитеdeleteдля него. - После deletion выведите
"Heap session destroyed"
- Создайте блок области видимости с помощью фигурных скобок
Это задание демонстрирует два основных способа вызова деструкторов: автоматически, когда объекты стека покидают область видимости, и вручную, когда вы удаляете объекты кучи. Оба пути должны корректно освобождать Dynamically выделенный журнал действий, чтобы предотвратить утечки памяти.
Подключите файл заголовка в main.cpp с помощью #include "Session.h".
Попробуйте сами
#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
// - Print "Stack session activities: <count>"
// Когда блок заканчивается, деструктор вызывается автоматически
// TODO: After the block, print "Stack session destroyed"
// TODO: Создайте Session, выделенный в куче, используя new
// - Username: "Guest", session ID: 202, log size: 3
// - Зарегистрируйте одну активность с кодом 5
// - Print "Heap session activities: <count>"
// - Удалите сессию
// TODO: After deletion, print "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Итоги — Обобщенный контейнерПотренируйтесь самостоятельно: Онлайн-компилятор C++