cout "глубина #" depth++ endl;
if ( v2 == 0 ) {
depth = 1;
return vl;
}
return traceGcd( v2, vl%v2 );
}
Значение, ассоциированное со статическим локальным объектом depth, сохраняется между вызовами traceGcd(). Его инициализация выполняется только один раз – когда к этой функции обращаются впервые. В следующей программе используется traceGcd():
#include iostream
extern int traceGcd(int, int);
int main() {
int rslt = traceCcd( 15, 123 );
cout "НОД (15,123): " rslt endl;
return 0;
}
Результат работы программы:
глубина #1
глубина #2
глубина #3
глубина #4
НОД (15,123): 3
Неинициализированные статические локальные объекты получают значение 0. А автоматические объекты в подобной ситуации получают случайные значения. Следующая программа иллюстрирует разницу инициализации по умолчанию для автоматических и статических объектов и опасность, подстерегающую программиста в случае ее отсутствия для автоматических объектов.
#include iostream
const int iterations = 2;
void func() {
int value1, value2; // не инициализированы
static int depth; // неявно инициализирован нулем
if ( depth iterations )
{ ++depth; func(); }
else depth = 0;
cout "\nvaluel:\t" value1;
cout "\tvalue2:\t" value2;
cout "\tsum:\t" value1 + value2;
}
int main() {
for ( int ix = 0; ix iterations; ++ix ) func();
return 0;
}
Вот результат работы программы:
valuel: 0 value2: 74924 sum: 74924
valuel: 0 value2: 68748 sum: 68748
valuel: 0 value2: 68756 sum: 68756
valuel: 148620 value2: 2350 sum: 150970
valuel: 2147479844 value2: 671088640 sum: -1476398812
valuel: 0 value2: 68756 sum: 68756
value1 и value2 – неинициализированные автоматические объекты. Их начальные значения, как можно видеть из приведенной распечатки, оказываются случайными, и потому результаты сложения непредсказуемы. Объект depth, несмотря на отсутствие явной инициализации, гарантированно получает значение 0, и функция func() рекурсивно вызывает сама себя только дважды.
8.4. Динамически размещаемые объекты
Время жизни глобальных и локальных объектов четко определено. Программист неспособен хоть как-то изменить его. Однако иногда необходимо иметь объекты, временем жизни которых можно управлять. Выделение памяти под них и ее освобождение зависят от действий выполняющейся программы. Например, можно отвести память под текст сообщения об ошибке только в том случае, если ошибка действительно имела место. Если программа выдает несколько таких сообщений, размер выделяемой строки будет разным в зависимости от длины текста, т.е. подчиняется типу ошибки, произошедшей во время исполнения программы.
Третий вид объектов позволяет программисту полностью управлять выделением и освобождением памяти. Такие объекты называют динамически размещаемыми или, для краткости, просто динамическими. Динамический объект “живет” в пуле свободной памяти, называемой хипом. Программист создает его с помощью оператора new, а уничтожает с помощью оператора delete. Динамически размещаться может как единичный объект, так и массив объектов. Размер массива, размещаемого в хипе, разрешается задавать во время выполнения.
В этом разделе, посвященном динамическим объектам, мы рассмотрим три формы оператора new: для размещения единичного объекта, для размещения массива и третью форму, называемую оператором размещения new (placement new expression). Когда хип исчерпан, этот оператор возбуждает исключение. (Разговор об исключениях будет продолжен в главе 11. В главе 15 мы расскажем об операторах new и delete применительно к классам.)
8.4.1. Динамическое создание и уничтожение единичных объектов
Оператор new состоит их ключевого слова new, за которым следует спецификатор типа. Этот спецификатор может относиться к встроенным типам или к типам классов. Например:
new int;
размещает в хипе один объект типа int. Аналогично в результате выполнения инструкции
new iStack;
там появится один объект класса iStack.