Программирование >>  Инициализация объектов класса, структура 

1 ... 221 222 223 [ 224 ] 225 226 227 ... 395


начало критического участка программе! #ifdef PROFILE

Timer t; #endif

критический участок t уничтожается автоматически отображается затраченное время ...

которые мы хотим профилировать, таким образом:

Чтобы убедиться в том, что мы понимаем поведение деструктора (да и конструктора

#include Account.h

Account global( James Joyce );

int main()

(1) (2) (3)

(5) Account local( Anna Livia Plurabelle , 10000 );

(6) Account &loc ref = global;

(7) Account *pact = 0; (8) (9) /1 n

(10) Account local too( Stephen Hero );

(11) pact = new Account( Stephen Dedalus );

(12) } (13)

(14) delete pact;

тоже), разберем следующий пример:

(15) }

Сколько здесь вызывается конструкторов? Чет1ре: один для глобального объекта global в строке (2); по одному для каждого из локальных объектов local и local too в строках (5) и (10) соответственно, и один для объекта, распределенного в хине, в строке (11). Ни объявление ссылки loc ref на объект в строке (6), ни объявление указателя pact в строке (7) не приводят к вызову конструктора. Ссылка - это псевдоним для уже сконструированного объекта, в данном случае для global. Указатель также лишь адресует объект, созданный ранее (в данном случае распределенный в хипе, строка (11)), или не адресует никакого объекта (строка (7)).

Аналогично вызываются четыре деструктора: для глобального объекта global, объявленного в строке (2), для двух локальных объектов и для объекта в хипе при вызове delete в строке (14). Однако в программе нет инструкции, с которой можно связать

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

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



необязательно: неявно выполняется компилятором

необязательны:

if (pact != 0 ) delete pact;

Всякий раз, когда внутри функции этот оператор применяется к отдельному объекту, размещенному в хипе, лучше использовать объект класса auto ptr, а не обычный указатель (см. обсуждение класса auto ptr в разделе 8.4). Это особенно важно потому, что пропущенный вызов delete (скажем, в случае, когда возбуждается исключение) ведет не только к утечке памяти, но и к пропуску вызова деструктора. Ниже приводится пример программы, переписанной с использованием auto ptr (она слегка модифицирована, так как объект класса auto ptr может быть явно переустановлен для

#include <memory>

#include Account.h

Account global( James Joyce );

int main()

Account local( Anna Livia Plurabelle ,

10000 );

Account sloc ref = global;

auto ptr<Account> pact( new Account( Stephen Dedalus )); {

Account local too( Stephen Hero );

объект auto ptr уничтожается здесь адресации другого объекта только присваиванием его другому auto ptr):

4 См. статью Джерри Шварца в [LIPPMAN96b], где приводится дискуссия по этому поводу и описывается решение, остающееся пока наиболее распространенным.

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

Конструкторы и деструкторы глобальных объектов вызываются на стадиях инициализации и завершения выполнения программ:. Хотя такие объекты нормально ведут себя при использовании в том файле, где они определены, но их применение в ситуации, когда производятся ссылки через границы файлов, становится в С++ серьезной проблемой.4

Деструктор не вызывается, когда из области видимости выходит ссылка или указатель на объект (сам объект при этом остается).

С++ с помощью внутренних механизмов препятствует применению оператора delete к указателю, не адресующему никакого объекта, так что соответствующие проверки кода



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

Image, но если мы применим оператор delete:

delete ptr;

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

ptr->~Image();

сохранив отведенную под изображение память для последующего вызова оператора размещения new.

Отметим, что, хотя ptr и arena адресуют одну и ту же область памяти в хипе,

деструктор не вызывается

применение оператора delete к arena

delete arena;

не приводит к вызову деструктора класса Image, так как arena имеет тип char*, а компилятор вызывает деструктор только тогда, когда операндом в delete является указатель на объект класса, имеющего деструктор.

14.3.1. Явный вызов деструктора

Иногда вызывать деструктор для некоторого объекта приходится явно. Особенно часто такая необходимость возникает в связи с оператором new (см. раздел 8.4). Рассмотрим пример. Когда мы пишем:

char *arena = new char[ sizeof Image ];

то из хипа выделяется память, размер которой равен размеру объекта типа Image, она не инициализирована и заполнена случайными битами. Если же написать:

Image *ptr = new (arena) Image( Quasimodo );

то никакой новой памяти не выделяется. Вместо этого переменной ptr присваивается адрес, ассоциированный с неременной arena. Теперь намять, на которую указывает ptr, интерпретируется как занимаемая объектом класса Image, и конструктор применяется к уже существующей области. Таким образом, оператор размещения new() позволяет сконструировать объект в ранее выделенной области памяти.

Закончив работать с изображением Quasimodo, м1 можем произвести какие-то операции с изображением Esmerelda, размещенным по тому же адресу arena в памяти:

Image *ptr = new (arena) Image( Esmerelda );

Однако изображение Quasimodo при этом будет затерто, а мы его модифицировали и хотели бы записать на диск. Обычно сохранение выполняется в деструкторе класса



1 ... 221 222 223 [ 224 ] 225 226 227 ... 395

© 2006 - 2025 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика