Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
OOP_otvety_k_ekzamenu.doc
Скачиваний:
55
Добавлен:
13.04.2015
Размер:
786.94 Кб
Скачать

7. Деструкторы классов, синтаксис, цель, моменты вызова деструкторов.

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

  1. Автоматический вызов при уничтожении объекта

  2. Однократность вызова в конце жизни объекта.

Деструктор также является специальным видом функции-члена, который ничего не возвращает, не разрешает взять собственный адрес и называется по схеме “символ-тильда ( ~ ) + имя класса”.

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

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

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

class MyClass

{

private:

Stack m_stack; // Дочерний объект с явно определенным декструктором

// Компилятор автоматически сгенерирует деструктор для MyClass:

// ~MyClass ()

// {

// Stack::~Stack( & m_stack );

// }

};

Также как и конструктор, вызывать деструктор в явном виде не приходится. Конкретный момент вызова деструктора определяется местом размещения объекта в памяти и временем жизни:

1. Глобальный объект (выделяется в сегменте данных)::

Stack g_Stack( 10 ); // ВЫЗОВ ДЕСТРУКТОРА ПРОИЗОЙДЕТ ПОСЛЕ ВЫПОЛНЕНИЯ ФУНКЦИИ main()

// Stack::~Stack( & g_Stack );

int main ()

{

// ...

}

2. Локальный автоматический объект (выделяется на стеке):

int main ()

{

Stack s( 10 );

// ...

// ВЫЗОВ ДЕСТРУКТОРА ПОМЕЩАЕТСЯ В ТОЧКЕ ВЫХОДА ОБЪЕКТА ИЗ ОБЛАСТИ ВИДИМОСТИ

// <--- Stack::~Stack( & s );

}

3. Локальный статический объект (выделяется в сегменте данных):

void f ()

{

static Stack s( 10 );

// ВЫЗОВ ДЕСТРУКТОРА ПОМЕЩАЕТСЯ В ТОЧКЕ ВЫХОДА ОБЪЕКТА ИЗ ОБЛАСТИ ВИДИМОСТИ

// ОДНАКО, ЭТОТ КОД БУДЕТ ЗАДЕЙСТВОВАН ЕСЛИ ФУНКЦИЯ f БУДЕТ ВЫЗВАНА ХОТЯ БЫ ОДИН РАЗ

// <--- Stack::~Stack( & s );

}

4. Объект в динамической памяти:

int main ()

{

Stack * pStack = new Stack( 10 );

// ...

delete pStack; // ВЫЗОВ ДЕСТРУКТОРА ЗА ШАГ ДО ОСВОБОЖДЕНИЯ ПАМЯТИ

// Stack::~Stack( pStack );

// ::operator delete( pStack );

}

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

int main ()

{

Stack stackA( 10 ); // Stack::Stack( & stackA, 10 );

Stack stackB( 15 ); // Stack::Stack( & stackB, 15 );

Stack stackC( 20 ); // Stack::Stack( & stackC, 20 );

// …

// ДЕСТРУКТОРЫ ВЫЗЫВАЮТСЯ В ПОРЯДКЕ, ОБРАТНОМ ПОРЯДКУ КОНСТРУИРОВАНИЯ

// Stack::~Stack( & stackC, 20 );

// Stack::~Stack( & stackB, 15 );

// Stack::~Stack( & stackA, 10 );

}

Следует уделять особое внимание уничтожению объектов, выделяемых динамически. Если не следить за освобождением ресурсов, это может привести к значительным утечкам памяти.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]