Бьерн Страуструп - Язык программирования С++. Главы 5-7 - Статическая память
ОГЛАВЛЕНИЕ
5.5.2 Статическая память
Рассмотрим такой пример:table tbl(100);Здесь конструктор, определенный в $$5.3.1, будет вызываться дважды: один раз для tbl и один раз для tbl2. Деструктор table::~table() также будет вызван дважды: для уничтожения tbl и tbl2 по выходе из main(). Конструкторы глобальных статических объектов в файле вызываются в том же порядке, в каком встречаются в файле описания объектов, а деструкторы для них вызываются в обратном порядке. Конструктор локального статического объекта вызывается, когда при выполнении программы первый раз встречается определение объекта.
void f(int i)
{
static table tbl2(i);
}
int main()
{
f(200);
// ...
}
Традиционно выполнение main() рассматривалось как выполнение всей программы. На самом деле, это не так даже для С. Уже размещение статического объекта класса с конструктором и (или) деструктором позволяет программисту задать действия, которые будут выполняться до вызова main()и (или) по выходе из main().
Вызов конструкторов и деструкторов для статических объектов играет в С++ чрезвычайно важную роль. С их помощью можно обеспечить соответствующую инициализацию и удаление структур данных, используемых в библиотеках. Рассмотрим <iostream.h>. Откуда берутся cin, cout и cerr? Когда они инициализируются? Более существенный вопрос: поскольку для выходных потоков используются внутренние буфера символов, то происходит выталкивание этих буферов, но когда? Есть простой и очевидный ответ: все действия выполняются соответствующими конструкторами и деструкторами до запуска main() и по выходе из нее (см. $$10.5.1). Существуют альтернативы использованию конструкторов и деструкторов для инициализации и уничтожения библиотечных структур данных, но все они или очень специализированы, или неуклюжи, или и то и другое вместе.
Если программа завершается обращение к функции exit(), то вызываются деструкторы для всех построенных статических объектов. Однако, если программа завершается обращением к abort(), этого не происходит. Заметим, что exit() не завершает программу немедленно. Вызов exit() в деструкторе может привести к бесконечной рекурсии. Если нужна гарантия, что будут уничтожены как статические, так и автоматические объекты, можно воспользоваться особыми ситуациями ($$9).
Иногда при разработке библиотеки бывает необходимо или просто удобно создать тип с конструктором и деструктором только для одной цели: инициализации и уничтожения объектов. Такой тип используется только один раз для размещения статического объекта, чтобы вызвать конструкторы и деструкторы.