Деструктор

Последнее обновление: 10.03.2023

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

  • когда завершается выполнение области видимости, внутри которой определены объекты

  • когда удаляется контейнер (например, массив), который содержит объекты

  • когда удаляется объект, в котором определены переменные, представляющие другие объекты

  • динамически созданные объекты удаляются при применении к указателю на объект оператора delete

По сути деструктор - это функция, которая называется по имени класса (как и конструктор) и перед которой стоит тильда (~):

~имя_класса() 
{
	// код деструктора
}

Деструктор не имеет возвращаемого значения и не принимает параметров. Каждый класс может иметь только один деструктор.

Обычно деструктор не так часто требуется и в основном используется для освобождения связанных ресурсов. Например, объект класса использует некоторый файл, и в деструкторе можно определить код закрытия файла. Или если в классе выделяется память с помощью оператора new, то в деструкторе можно освободить подобную память.

Сначала рассмотрим простейшее определение деструктора:

#include <iostream>

class Person
{
public:
	Person(std::string p_name)
	{
		name = p_name;
        std::cout << "Person " << name << " created" << std::endl;
	}
    ~Person()
    {
        std::cout << "Person " << name << " deleted" << std::endl;
    }
private:
	std::string name;
};

int main()
{
    {
        Person tom{"Tom"};
        Person bob{"Bob"};
    }   // объекты Tom и Bob уничтожаются

    Person sam{"Sam"};
}   // объект Sam уничтожается

В классе Person определен деструктор, который просто уведомляет об уничтожении объекта:

~Person()
{
	std::cout << "Person " << name << " deleted" << std::endl;
}

В функции main создаются три объекта Person. Причем два из них создается во вложенном блоке кода.:

{
    Person tom{"Tom"};
    Person bob{"Bob"};
}

Этот блок кода задается границы области видимости, в которой существуют эти объекты. И когда выполнение блока завершается, то уничтожаются обе переменных, и для обоих объектов вызываются деструкторы.

После этого создается третий объект - sam

int main()
{
    {
        Person tom{"Tom"};
        Person bob{"Bob"};
    }   // объекты Tom и Bob уничтожаются

    Person sam{"Sam"};
}   // объект Sam уничтожается

Поскольку он определен в контексте функции main, то и уничтожается при завершении этой функции. В итоге мы получим следующий консольный вывод:

Person Tom created
Person Bob created
Person Bob deleted
Person Tom deleted
Person Sam created
Person Sam deleted

Чуть более практический пример. Допустим, у нас есть счетчик объектов Person в виде статической переменной. И если в конструкторе при создании каждого нового объекта счетчик увеличивается, то в деструкторе мы можем уменьшать счетчик:

#include <iostream>

class Person
{
public:
	Person(std::string p_name)
	{
		name = p_name;
        ++count;
        std::cout << "Person " << name << " created. Count: " << count << std::endl;
	}
    ~Person()
    {
        --count;
        std::cout << "Person " << name << " deleted. Count: " << count << std::endl;
    }
private:
	std::string name;
    static inline unsigned count{}; // счетчик объектов
};

int main()
{
    {
        Person tom{"Tom"};
        Person bob{"Bob"};
    }   // объекты Tom и Bob уничтожаются
    Person sam{"Sam"};
}   // объект Sam уничтожается

Консольный вывод программы:

Person Tom created. Count: 1
Person Bob created. Count: 2
Person Bob deleted. Count: 1
Person Tom deleted. Count: 0
Person Sam created. Count: 1
Person Sam deleted. Count: 0

При этом выполнение самого деструктора еще не удаляет сам объект. Непосредственно удаление объекта производится в ходе явной фазы удаления, которая следует после выполнения деструктора.

Стоит также отметить, что для любого класса, который не определяет собственный деструктор, компилятор сам создает деструктор. Например, если бы класс Person не имел бы явно определенного деструктора, то для него автоматически создавался бы следующий деструктор:

~Person(){}
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850