|
Программирование >> Инициализация объектов класса, структура
(a) extern int ix = 1024; (b) int iy; (c) extern void reset( void *p ) { /* ... */ } (d) extern const int *pi; определениями, и почему: (e) void print( const matrix & ); Упражнение 8.4 Какие из приведенных ниже объявлений и определений вы поместили бы в заголовочный (a) int var; (b) inline bool is eal( const SmallInt &, const SmallInt & ){ } (c) void putValues( int *arr, int size ); (d) const double pi = 3.1416; файл? В исходный файл? Почему? (e) extern int total = 255; 8.3. Локальные объекты Объявление переменной в локальной области видимости вводит локальный объект. Существует три вида таких объектов: автоматические, регистровые и статические, различающиеся временем жизни и характеристиками занимаемой памяти. Следовательно, встроенная функция, необходимая в нескольких исходных файлах, должна быть определена в заголовочном файле. Однако спецификация inline - только совет компилятору. Будет ли функция встроенной везде или только в данном конкретном месте, зависит от множества обстоятельств. Если компилятор пренебрегает спецификацией inline, он генерирует определение функции в исполняемом файле. Если такое определение появится в данном файле больше одного раза, это будет означать ненужную трату памяти. Большинство компиляторов выдают предупреждение в любом из следующих случаев (обычно это требует включения режима выдачи предупреждений): само определение функции не позволяет встроить ее. Например, она слишком сложна. В таком случае попробуйте переписать функцию или уберите спецификацию inline и поместите определение функции в исходный файл; конкретный вызов функции может не быть подставлен по месту . Например, в оригинальной реализации С++ компании AT&T (cfront) такая подстановка невозможна для второго вызова в пределах одного и того же выражения. В такой ситуации выражение следует переписать, разделив вызовы встроенных функций. Перед тем как употребить спецификацию inline, изучите поведение функции во время выполнения. Убедитесь, что ее действительно можно встроить. М1 не рекомендуем объявлять функции встроенными и помещать их определения в заголовочный файл, если они не могут быть таковыми по своей природе. Упражнение 8.3 Установите, какие из приведенных ниже инструкций являются объявлениями, а какие - #include Matrix.h Matrix* trouble( Matrix *pm ) Matrix res; какие-то действия результат присвоим res return &res; плохо! int main() { Matrix m1; ... Matrix *mainResult = trouble( &m1 ); ... выполнения функции будет относиться к несуществующему объекту: mainResult получает значение адреса автоматического объекта res. К несчастью, память, отведенная под res, освобождается по завершении функции trouble() . После возврата в main() mainResult указывает на область памяти, не отведенную никакому объекту. (В данном примере эта область все еще может содержать правильное значение, поскольку мы не вызывали других функций после trouble() и запись ее активации, вероятно, еще не затерта.) Подобные ошибки обнаружить весьма трудно. Дальнейшее использование mainResult в программе скорее всего даст неверные результаты. Передача в функцию trouble() адреса m1 автоматического объекта функции main() безопасна. Память, отведенная main() , во время вызова trouble() находится в стеке, так что m1 остается доступной внутри trouble() . Автоматический объект существует с момента активизации функции, в которой он определен, до выхода из нее. Регистровый объект - это автоматический объект, для которого поддерживается быстрое считывание и запись его значения. Локальный статический объект располагается в области памяти, существующей на протяжении всего времени выполнения программы. В этом разделе мы рассмотрим свойства всех этих объектов. 8.3.1. Автоматические объекты Автоматический объект размещается в памяти во время вызова функции, в которой он определен. Память для него отводится из программного стека в записи активации функции. Говорят, что такие объекты имеют автоматическую продолжительность хранения, или автоматическую протяженность. Неинициализированный автоматический объект содержит случайное, или неопределенное, значение, оставшееся от предыдущего использования области памяти. После завершения функции ее запись активации выталкивается из программного стека, т.е. память, ассоциированная с локальным объектом, освобождается. Время жизни такого объекта заканчивается с завершением работы функции, и его значение теряется. Поскольку память, отведенная локальному объекту, освобождается при завершении работы функции, адрес автоматического объекта следует использовать с осторожностью. Например, этот адрес не может быть возвращаемым значением, так как после 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 (со статической продолжительностью хранения). Хотя значение такого объекта сохраняется между вызовами функции, в которой он определен, видимость его имени ограничена локальной областью. Статический локальный объект инициализируется во время первого Если адрес автоматического объекта сохраняется в указателе, время жизни которого больше, чем самого объекта, такой указатель называют висячим. Работа с ним - это серьезная ошибка, поскольку содержимое адресуемой области памяти непредсказуемо. Если комбинация бит по этому адресу оказывается в какой-то степени допустимой (не приводит к нарушению защиты памяти), то программа будет выполняться, но результаты ее будут неправильными. 8.3.2. Регистровые автоматические объекты Автоматические объект:, интенсивно используем1е в функции, можно объявить с ключевым словом register, тогда компилятор будет их загружать в машинные регистры. Если же это невозможно, объекты останутся в основной памяти. Индексы массивов и указатели, встречающиеся в циклах, - хорошие кандидаты в регистровые
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0.001
При копировании материалов приветствуются ссылки. |