Программирование >>  Инициализация объектов класса, структура 

1 ... 125 126 127 [ 128 ] 129 130 131 ... 395


#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 );

gcd() ,устанавливающая глубину рекурсии с его помощью:

Значение, ассоциированное со статическим локальным объектом depth, сохраняется между вызовами traceGcd() . Его инициализация выполняется только один раз - когда к

#include <iostream>

extern int traceGcd(int, int);

int main() {

int rslt = traceCcd( 15, 123 ); cout << НОД (15,123): << rslt << endl;

cout

return 0;

этой функции обращаются впервые. В следующей программе используется traceGcd() :

Результат работы программы:

глубина #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.

Сам по себе оператор new не слишком полезен. Как можно реально воспользоваться созданным объектом? Одним из аспектов работы с памятью из хина является то, что размещаемые в ней объекты не имеют имени. Оператор new возвращает не сам объект, а указатель на него. Все манипуляции с этим объектом производятся косвенно через указатели:

int *pi = new int;

Здесь оператор new создает один объект типа int, на который ссылается указатель pi. Выделение памяти из хипа во время выполнения программы называется динамическим выделением. Мы говорим, что намять, адресуемая указателем pi, выделена динамически.

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

if ( *pi == 0 )

вероятно, даст false, поскольку объект, на который указывает pi, содержит случайную последовательность битов. Следовательно, объекты, создаваемые с помощью оператора new, рекомендуется инициализировать. Программист может инициализировать объект типа int из предыдущего примера следующим образом:

int *pi = new int( 0 );

Константа в скобках задает начальное значение для создаваемого объекта; теперь pi ссылается на объект типа int, имеющий значение 0. Выражение в скобках называется инициализатором. Это может быть любое выражение (не обязательно константа), возвращающее значение, приводимое к типу int.



1 ... 125 126 127 [ 128 ] 129 130 131 ... 395

© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика