Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
c_1_po_16.docx
Скачиваний:
21
Добавлен:
06.12.2018
Размер:
71 Кб
Скачать
☆

10) Стековые и динамические объекты, указатели и ссылки, достоинства и недостатки стековых объектов.

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

Размещение в стеке

Чтобы выделить память для стековой переменной в области действия блока, достаточно просто объявить ее обычным образом.

{

int i;

foo f(constructor_args);

// Перед выходом из блока вызываются деструкторы i и f

}

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

{

int i;

foo f;

SomeFunction(&f);

}

Без изучения функции SomeFunction невозможно сказать, безопасен ли этот фрагмент. SomeFunction может передать адрес дальше или сохранить его в какой-нибудь переменной, а по закону Мэрфи этот адрес наверняка будет использован уже после уничтожения объекта f. Даже если сверхтщательный анализ SomeFunction покажет, что адрес не сохраняется после вызова, через пару лет какой-нибудь новый программист модифицирует SomeFunction, продлит существование адреса на пару машинных команд и — БУМ!!! Лучше полностью исключить такую возможность и не передавать адреса стековых объектов.

Динамическое размещение

Чтобы выделить память для объекта в куче (heap), воспользуйтесь оператором new.

foo* f = new foo(constructor_args);

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

Указатели и ссылки

Попытки связать указатели с динамическими объектами часто приводят к недоразумениям. В сущности, они не имеют друг с другом ничего общего. Вы можете получить адрес стекового объекта и выполнить обратное преобразование, то есть разыменование (dereferencing) адреса динамического объекта. И на то, и на другое можно создать ссылку.

{

foo f;

foo* p = &f;

f.MemberFn(); // Использует сам объект

p->MemberFn(); // Использует его адрес

p = new foo;

foo& r = *p; // Ссылка на объект

r.MemberFn(); // То же, что и p->MemberFn()

}

Как видите, выбор оператора . или -> зависит от типа переменной и не имеет отношения к атрибутам самого объекта. Раз уж мы заговорили об этом, правильные названия этих операторов (. и ->) — селекторы членов класса (member selectors).

Недостатки стековых объектов

Если использовать оператор delete для стекового объекта, то при большом везении ваша программа просто грохнется. А если вам (как и большинству из нас) не повезет, то программа начнет вести себя, как ревнивая любовница — она будет вытворять, всякие гадости в разных местах памяти, но не скажет, на что же она разозлилась. Дело в том, что в большинстве реализаций C++ оператор new записывает пару скрытых байтов перед возвращаемым адресом. В этих байтах указывается размер выделенного блока. По ним оператор delete определяет, сколько памяти за указанным адресом следует освободить. При выделении памяти под стековые объекты оператор new не вызывается, поэтому эти дополнительные данные отсутствуют. Если вызвать оператор delete для стекового объекта, он возьмет содержимое стека над вашей переменной и интерпретирует его как размер освобождаемого блока.

Итак, мы знаем по крайней мере две причины, по которым следует избегать стековых объектов — если у вас нет действительно веских доводов в их пользу:

1. Адрес стекового объекта может быть сохранен и использован после выхода за границы области действия объекта.

2. Адрес стекового объекта может быть передан оператору delete.

Следовательно, для стековых объектов действует хорошее правило: Никогда не получайте их адреса или адреса их членов.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]