Статические локальные объекты
Внутри функции или составной инструкции можно объявить объект с локальной областью видимости, который, однако, будет существовать в течение всего времени выполнения программы. Если значение локального объекта должно сохраняться между вызовами функции, то обычный автоматический объект не подойдет: ведь его значение теряется каждый раз после выхода.
В таком случае локальный объект необходимо объявить как static (со статической продолжительностью хранения). Хотя значение такого объекта сохраняется между вызовами функции, в которой он определен, видимость его имени ограничена локальной областью. Статический локальный объект инициализируется во время первого выполнения инструкции, где он объявлен. Вот, например, версия функции gcd(),устанавливающая глубину рекурсии с его помощью:
#include <iostream> int traceGcd( int vl, int v2 ) { static int depth = 1; 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()
рекурсивно вызывает сама себя только дважды.