Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Методичка - Основи Програмування C_.doc
Скачиваний:
46
Добавлен:
18.12.2018
Размер:
1.44 Mб
Скачать

4. Деструктор класу.

Деструктор (фіналізатор – finalyzer) класу – це метод класу, що викликається автоматично в момент знищення екземпляру. Його призначення – вивільнити певні ресурси, які, можливо, використав конструктор при створенні об’єкту. На відміну від класичного варіанту мови С++, де втрачені посилання постають великою проблемою, у .NET існує система GC – Garbage Collector автоматичного знищення об’єктів, посилань на які не існує в даний момент. Якщо у класі визначений деструктор (а це, як ми бачили, зовсім не обов’язково), то він напевне буде викликаний, проте не можна точно визначити момент, коли об’єкт буде фізично знищеним. Це накладає певні застереження на використання деструкторів, якщо вони мають виконувати якісь важливі дії на певний момент часу.

Деструктор має ідентифікатор, що починається із знака операції (~), після якого слідує ідентифікатор класу. Так само як конструктор, деструктор не має типу результату, крім того, він не має специфікатору доступу та параметрів – отже, не перевантажується.

У наступному прикладі клас Destructor містить цілочисельний член класу kod та конструктор, що його ініціалізує та інформує про створення об’єкту. Деструктор класу містить одну інструкцію – повідомлення про знищення об’єкту. Мета цього прикладу – дослідити порядок викликів деструкторів. З цією метою у програму включимо ще один метод void creator(int k), у якому створюється локальний об’єкт Destructor d. Цей об’єкт існує лише протягом роботи функції creator. Посилання на нього втрачає сенс в момент завершення функції creator. Але в який момент він буде знищений фізично? Щоб відповісти на це питання, у функції Main створимо у циклі дуже багато звертань до функції creator. При кожному звертанні створюватиметься новий локальний об’єкт класу Destructor, а кожний попередній помічатиметься як посилання, не пов’язане з жодним об’єктом. В залежності від швидкодії вашого комп’ютера кількість ітерацій циклу можна зменшити або збільшити. Через кожні 10000 кроків циклу змоделюємо затримку, щоб краще відслідкувати результат. Ви побачите, що об’єкти знищуються не зовсім у хронологічному порядку.

using System;

namespace Destructor

{

class Program

{

class Destructor

{

public int kod;

public Destructor(int kod_)

{

kod = kod_;

Console.WriteLine("Створюється екземпляр {0}", kod);

}

~Destructor()

{

Console.WriteLine("Знищується екземпляр {0}", kod);

}

}

static void creator(int k)

{

Destructor d = new Destructor(k);

}

static void Main()

{

for (int i = 1; i < 40000; i++)

{

creator(i);

if ((i % 10000) == 0) Console.ReadLine();

}

}

}

}

Отже, на відміну від мови С++, в якій об’єкти створюються командою new , а знищуються командою delete , яка гарантує в цей момент виклик деструктора, в мові С# знищенням об’єктів керує система GC, а тому наявність деструктора не є обов’язковою для звичайних класів.

Система GC працює автоматично, вона гарантує, що непотрібні об’єкти знищуються та причому дана операція виконується лише один раз, а також, що знищуються лише ті об’єкти, на які немає жодного посилання. Тим самим виключаються стандартні проблеми при роботі з динамічною пам’яттю – наприклад, проблема втрачених посилань або витік пам’яті (коли на об’єкт немає посилань, тобто до нього неможливо отримати доступ, але він не знищений і займає місце у пам’яті) або проблема завислих вказівників (коли об’єкта вже немає, а посилання на відповідне місце у пам’яті існує).

Система GC використовує два варіанти роботи очистки динамічної пам’яті – окремо для порівняно малих об’єктів та порівняно великих. Збирач сміття запускається через певні проміжки часу і для малих об’єктів знищує вже непотрібні і одразу дефрагментує динамічну пам’ять, переписуючи дані так, що об’єкти стають розташовані поруч (тобто створює неперервну вільну область динамічної пам’яті), при цьому відповідним чином автоматично змінює посилання на ті об’єкти, які залишаються у динамічній пам’яті. Для порівняно великих об’єктів алгоритм роботи збирача сміття ускладнюється та використовується поняття покоління, до якого належить об’єкт. Всього поколінь три: 0, 1 та 2. В момент створення усі об’єкти належать поколінню 0. Через деякий час збирач сміття видаляє непотрібні об’єкти, а ті, що залишилися, переводяться у покоління 1. Покоління 1 «чиститься» рідше за покоління 0, але за тим самим принципом. Об’єкти покоління 1, які залишаються у пам’яті після видалення непотрібних, переходять у покоління 2 (воно є останнім можливим).