Бьерн Страуструп.
Язык программирования С++
277
Здесь возникает вопрос, как реализация может обеспечить создание предопределенных потоков cout,
cin и cerr до их первого использования и закрытие их только после последнего использования. Конечно,
разные реализации библиотеки потоков из
могут по-разному решать эту задачу. В конце
концов, решение – это прерогатива реализации, и оно должно быть скрыто от пользователя. Здесь
приводится только один способ, примененный только в одной реализации, но он достаточно общий,
чтобы гарантировать правильный порядок создания и уничтожения глобальных объектов различных
типов.
Основная идея в том, чтобы определить вспомогательный класс, который по сути служит счетчиком,
следящим за тем, сколько раз был включен в раздельно компилировавшиеся программные
файлы:
class Io_init {
static int count;
//...
public:
Io_init();
^Io_init();
};
static Io_init io_init ;
Для каждого программного файла определен свой объект с именем io_init. Конструктор для объектов
io_init использует Io_init::count как первый признак того, что действительная инициализация глобальных
объектов потоковой библиотеки ввода-вывода сделана в точности один раз:
Io_init::Io_init()
{
if (count++ == 0) {
// инициализировать cout
// инициализировать cerr
// инициализировать cin
// и т.д.
}
}
Обратно, деструктор для объектов io_init использует Io_count, как последнее указание на то, что все
потоки закрыты:
Io_init::^Io_init()
{
if (--count == 0) {
// очистить cout (сброс, и т.д.)
// очистить cerr (сброс, и т.д.)
// очистить cin
// и т.д.
}
}
Это общий прием работы с библиотеками, требующими инициализации и удаления глобальных
объектов. Впервые в С++ его применил Д. Шварц. В системах, где при выполнении все программы
размещаются в основной памяти, для этого приема нет помех. Если это не так, то накладные расходы,
связанные с вызовом в память каждого программного файла для выполнения функций инициализации,
будут заметны. Как всегда, лучше, по возможности, избегать глобальных объектов. Для классов, в
которых каждая операция значительна по объему выполняемой работы, чтобы гарантировать
инициализацию, было бы разумно проверять такие первые признаки (наподобие Io_init::count) при
каждой операции. Однако, для потоков такой подход был бы излишне расточительным.
Достарыңызбен бөлісу: