40
Foo* aGlobalFoo;
void Library::OpenLibrary()
{
aGlobal = 17;
aGlobalFoo = new Foo;
}
void Library::CloseLibrary()
{
aGlobal = 0;
delete
aGlobalFoo;
aGlobalFoo
=
NULL;
}
К этому нужно привыкнуть. А происходит следующее: файл .h компилируется со множеством других
файлов .срр, один из которых - Library.cpp. Порядок инициализации
глобальных объектов,
встречающихся в этих файлах, предсказать невозможно. Тем не менее, каждый из них будет иметь
свою статическую копию
LibraryDummy
. При каждой инициализации файла .срр, в который включен
файл Library.h, конструктор
LibraryDummy
увеличивает счетчик.
При выходе из
main()
или при
вызове
exit()
файлы .срр уничтожают глобальные объекты и уменьшают счетчик в деструкторе
LibraryDummy
. Конструктор и деструктор гарантируют, что
OpenLibrary()
и
CloseLibrary()
будут вызваны ровно один раз.
Этот прием приписывается многим разным программистам, но
самый известный пример его
использования встречается в библиотеке iostream. Там он инициализирует большие структуры данных,
с которыми работает библиотека, ровно один раз и лишь тогда, когда это требуется.
Деструкторы
Деструкторы вызываются каждый раз, когда стековый объект выходит из области действия (включая
анонимные экземпляры и временные объекты, создаваемые компилятором) или когда для
динамического объекта вызывается оператор
delete
. К деструкторам
относится ряд малоизвестных
фактов.
Порядок вызова
Деструкторы гарантированно
вызываются в порядке, обратном порядку вызова конструкторов. Это
означает, что сначала вызывается тело конструктора объекта, затем деструкторы переменных класса в
порядке, обратном порядку их перечисления в объявлении класса, и наконец деструкторы базовых
классов, начиная с последнего в списке наследования и кончая первым базовым первого базового и т.д.
Уничтожение глобальных объектов
Если от разговоров об инициализации глобальных объектов у
вас закружилась голова, могу вас
обрадовать. Если разработчик вашего компилятора справился со своей работой, деструкторы
глобальных объектов гарантированно вызываются в порядке, точно обратном порядку вызова
конструкторов.
Глобальные объекты уничтожаются при выходе из области действия
main()
или при вызове
exit()
.
Невиртуальные деструкторы
C++ выбирает вызываемый деструктор по типу указателя на объект. Если указатель имеет тип
base*
(указатель на базовый класс), возникнут проблемы, если только деструктор класса не виртуален.
class Foo {
public:
~Foo();
};