Menu
Coddy logo textTech

Глубокое погружение в деструкторы

Часть раздела Объектно-ориентированное программирование путешествия по 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 (выходит из области видимости)

В отличие от конструкторов, класс может иметь только один деструктор. Его нельзя перегружать.

Если вы не определите его, компилятор создаст деструктор по умолчанию, который не делает ничего особенного — он просто уничтожает каждый член класса. Для классов, управляющих ресурсами, вы должны написать свой собственный деструктор, чтобы предотвратить утечки памяти.

challenge icon

Задание

Легко

Давайте создадим менеджер сессий, который отслеживает активные сессии пользователей и демонстрирует, как деструкторы автоматически очищают ресурсы при уничтожении объектов — независимо от того, выходят ли они из области видимости или удаляются явно.

Вы создадите два файла для организации вашего кода:

  • 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;
}
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Объектно-ориентированное программирование