Дестру́ктор — специальный метод класса, служащий для деинициализацииобъекта (например освобождения памяти).
Синтаксис деструктора
- C++: имя деструктора совпадает с именем класса, перед которым стоит символ тильда (~). См. пример ниже.
- D: деструкторы имеют имя
~this(). - Rust: деструкторы построены на типаже
Drop. - Delphi: деструкторы имеют ключевое слово
destructorи могут иметь любое имя, но обычно именуется какDestroy. - Object Pascal: деструкторы имеют ключевое слово
destructorи могут иметь любое имя, но обычно именуется какDestroy. - Objective-C: деструкторы имеют имя
dealloc. - Perl: деструкторы имеют имя
DESTROY; в расширении Moose для Perl 5, деструкторы имеют названиеDEMOLISH. - PHP: В PHP 5+, деструкторы имеют имя
__destruct. В более ранних версиях PHP деструкторов не было.[1] - Python: есть методы с именем
__del__, называемые деструкторами в руководстве по языку Python 2,[2] но на самом деле они являются финализаторами, как это объявлено в Python 3.[3] - Swift: деструкторы имеют имя
deinit.
Деструктор в Delphi
Для объявления деструктора в Delphi используется ключевое слово destructor. Имя деструктора может быть любым, но рекомендуется всегда называть деструктор Destroy.
TClassWithDestructor = class destructor Destroy; override; end;В Delphi все классы являются потомками, по крайней мере, класса TObject, поэтому, для корректного освобождения памяти, необходимо перекрывать деструктор, используя директиву override.
В Delphi прямой вызов деструктора используется редко. Вместо него используют метод Free.
MyObject.Free;
Метод Free вначале проверяет существует ли уничтожаемый объект, а затем вызывает деструктор. Этот прием позволяет избегать ошибок, возникающих при обращении к несуществующему объекту.
Деструктор в C++
#include using namespace std; class NameOfClass { private: int a; public: NameOfClass(int m); ~NameOfClass(); }; NameOfClass::~NameOfClass() { cout << this->a << endl; } NameOfClass::NameOfClass(int m) { a = m; }~NameOfClass() — деструктор, имеет имя ~NameOfClass, не имеет входных параметров.
В данном случае при уничтожении объекта выводит в консоль параметр a.
Деструктор в Python
В Python поддерживаются деструкторы и для них есть ключевое слово del, но, в отличие от delete в C++, del только уменьшает счетчик ссылок на объект и не обязательно немедленно уничтожает объект.
class Destructible:def __init__(self,name:str)->None:self.name:str=nameprint(f"Created Destructible: {self.name}")def __del__(self)->None:print(f"Destructor called for: {self.name}")if__name__=="__main__":d:Destructible=Destructible("My name")print(f"Using Destructible: {d.name}")deldПодобно Java и C#, в Python есть блок try-with-resources, называемый блоком with или «контекстным менеджером». Он используется для таких вещей, как файлы и сетевые соединения.
from typing importOptionalclass Destructible:def __init__(self,name:str)->None:self.name:str=namedef __enter__(self)->"Destructible":print(f"Entering context (allocating resource: {self.name})")returnselfdef __exit__(self,exc_type:Optional[type],exc_val:Optional[Exception],exc_tb:Optional[type])->None:print(f"Exiting context (cleaning up resource: {self.name})")if__name__=="__main__":withDestructible("Resource A")asd:print(f"Using resource {d.name} inside context")# Most Python standard library resources support with blocks:withopen(file_path,"r")asfile:print("Reading the file content:")content:str=file.read()print(content)Деструктор в Rust
struct Foo { i: i32,}impl Foo { fn new(i: i32) -> Foo { Foo { i } }}impl Drop for Foo { fn drop(&mut self) { println!("{}", self.i); }}В блоке impl для структуры Foo реализуется одноимённый метод типажа Drop[4]. В коде ниже создаётся переменная foo. Благодаря умной модели памяти, деструктор будет вызван автоматически и без накладных расходов, как только закончится область видимости переменной.
let foo = Foo::new(42);Виртуальный деструктор
Деструктор интерфейсов или абстрактных классов обычно делают виртуальным. Такой прием позволяет корректно удалять без утечек памяти, имея лишь указатель на базовый класс[5].
Пусть (на C++) есть тип Father и порождённый от него тип Son:
class Father{public: Father() {} ~Father() {} };class Son : public Father{public: int* buffer; Son() : Father() { buffer = new int[1024]; } ~Son() { delete[] buffer; }};Нижеприведённый код является некорректным и приводит к утечке памяти.
Father* object = new Son(); // вызывается Son()delete object; // вызывается ~Father()!!Однако, если сделать деструктор Father виртуальным:
class Father{public: Father() {} virtual ~Father() {} };class Son : public Father{private: int* buffer;public: Son() : Father() { buffer = new int[1024]; } ~Son() { delete[] buffer; }};вызов delete object; приведет к последовательному вызову деструкторов ~Son и ~Father.
Ссылки
- ↑ДеструкторыАрхивная копия от 30 августа 2019 на Wayback Machine, в онлайн документации по PHP
- ↑3. Data model — Python 2.7.18 documentation. Дата обращения: 31 августа 2019. Архивировано 19 сентября 2019 года.
- ↑3. Data model — Python 3.9.0 documentation. Дата обращения: 31 августа 2019. Архивировано 26 октября 2012 года.
- ↑std::ops::Drop - Rust. doc.rust-lang.org. Дата обращения: 31 октября 2019. Архивировано 29 сентября 2019 года.
- ↑Сергей Оленда́ренко. Виртуальные функции и деструктор. Дата обращения: 1 июля 2013. Архивировано 2 августа 2013 года.