Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Липпман.doc
Скачиваний:
7
Добавлен:
14.08.2019
Размер:
7.54 Mб
Скачать

8.3.2. Регистровые автоматические объекты

Автоматические объекты, интенсивно используемые в функции, можно объявить с ключевым словом register, тогда компилятор будет их загружать в машинные регистры. Если же это невозможно, объекты останутся в основной памяти. Индексы массивов и указатели, встречающиеся в циклах, – хорошие кандидаты в регистровые объекты.

for ( register int ix =0; ix < sz; ++-ix ) // ...


for ( register int *p = array ; p < arraySize; ++p ) // ...

Параметры также можно объявлять как регистровые переменные:

bool find( register int *pm, int Val ) {

while ( *pm )

if ( *pm++ == Val ) return true;

return false;


}

Их активное использование может заметно увеличить скорость выполнения функции.

Указание ключевого слова register – только подсказка компилятору. Некоторые компиляторы игнорируют такой запрос, применяя специальные алгоритмы для определения наиболее подходящих кандидатов на размещение в свободных регистрах.

Поскольку компилятор учитывает архитектуру машины, на которой будет выполняться программа, он зачастую может принять более обоснованное решение об использовании машинных регистров.

8.3.3. Статические локальные объекты

Внутри функции или составной инструкции можно объявить объект с локальной областью видимости, который, однако, будет существовать в течение всего времени выполнения программы. Если значение локального объекта должно сохраняться между вызовами функции, то обычный автоматический объект не подойдет: ведь его значение теряется каждый раз после выхода.

В таком случае локальный объект необходимо объявить как 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() рекурсивно вызывает сама себя только дважды.