Студопедия — Локальное и динамическое распределение памяти
Студопедия Главная Случайная страница Обратная связь

Разделы: Автомобили Астрономия Биология География Дом и сад Другие языки Другое Информатика История Культура Литература Логика Математика Медицина Металлургия Механика Образование Охрана труда Педагогика Политика Право Психология Религия Риторика Социология Спорт Строительство Технология Туризм Физика Философия Финансы Химия Черчение Экология Экономика Электроника

Локальное и динамическое распределение памяти






Локальное распределение (local allocation) означает, что память для переменной или объекта выделяется в программном стеке.

Стек (stack) - это область оперативной памяти, резервируемая программой при запуске.

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

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

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

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

Динамическое распределение (dynamic allocation) означает, что память для объектов выделяется в « куче ».

Под « кучей » ( heap ) в Windows-программах понимается вся виртуальная память компьютера - это свободная память, которая выделяется во время выполнения программы. Доступ к переменным в этой памяти выполняется через указатели.

В С/С++ есть два способа работы с динамической памятью:

§ семейство функций malloc()и free() (наследие С);

§ применение операторов new и delete.

 

В первом случае нужно использовать функции распределения динамической памяти, которая описана в библиотеке alloc.h. Виды функций:

1) Void *malloc (unsigned s) – выделяет память размером s байт.

2) Void *calloc (unsigned nel, unsigned els) – выделяют память для nel
элементов для которой размер каждого элемента равен els.

3) Void *realloc (void *blok, unsigned s) – изменяет размер ранее выявленной памяти. Для * blok до величины s байт.

4) Void far *faralloc (unsigned long nel, unsigned long els) – выделяет память для дальней её модели под nel элементов размер каждого из которых равен els.

5) Void free (void *blok) – освобождает ранее выделенную память.

Во втором случае имеет место следующее:

Статическое объявление Динамическое объявление
int ia; int *ia = new int; //выделение переменной delete ia; //удаление переменной и освобождение памяти;  
int arr[10]; int *arr; arr = new int[10]; // выделение массива переменных; delete [] arr; // удаление переменной и освобождение памяти;
   

 

Если оператор new не может выделить запрашиваемую память, он возвращает NULL. Теоретически вы должны проверить указатель после вызова new и убедиться, что он имеет ненулевое значение.

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

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

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

Освобождение памяти, выделенной с помощью оператора new, осуществляется оператором delete.

Каждому new должен соответствовать свой delete. Если вы не освободите всю память, распределенную с помощью оператора new, ваша программа вызовет «утечку» памяти в системе. Будьте аккуратны в использовании пары new/delete.

Использование оператора delete крайне просто:

SomeObject* myObject = new SomeObject;

// использование myObject

delete myObject; // до свидания!

Вот и все! Вам следует только знать некоторые особенности использования delete с указателями. Во-первых, нельзя применять оператор delete к указателю дважды, в противном случае может возникнуть нарушение защиты и прочие неприятности. Во-вторых, вполне допустимо применять delete к указателю, установленному в 0. Но чему это соответствует на практике? Сейчас объясню.

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

Я говорил раньше, что стоит инициализировать указатели нулем, если вы не используете их немедленно. Для этого есть две причины. Об одной я уже говорил (неинициализированный указатель содержит случайное значение, что нежелательно). Вторая заключается в том, что к указателю со значением NULL можно применить delete независимо от того, был ли этот указатель ранее использован:

Monster* swampThing = 0;

// затем, при выходе из программы...

delete swampThing;

В этом случае вам не нужно думать о том, была ли когда-нибудь выделена память под объект. Использование delete безопасно, если указатель содержит адрес объекта или NULL.

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

Monster* borg = new Monster;

// затем...

delete borg;

borg = 0;

Теперь повторный вызов delete безопасен - указатель содержит NULL.

Другой способ решения проблемы повторного уничтожения объекта - сравнение указателя с нулем до вызова delete:

if(swampThing) delete swampThing;

При этом предполагается, что вы установили указатель в 0 после уничтожения объекта в другой части программы. Можно использовать любой из способов; главное, чтобы вы не забывали это делать всякий раз, когда возможно повторное применение оператора delete к указателю.

Ecли вы используете ссылку при динамическом создании объекта, синтаксис оператора delete немного меняется. Вот пример:

MyStruct& ref = *new MyStruct;

ref.X = 100;

// затем...

delete &ref;

Вместе со ссылкой необходимо использовать оператор взятия адреса. Помните, что ссылку нельзя установить в 0, поэтому будьте внимательны, чтобы не применить оператор delete дважды.







Дата добавления: 2015-08-12; просмотров: 1439. Нарушение авторских прав; Мы поможем в написании вашей работы!



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

Расчетные и графические задания Равновесный объем - это объем, определяемый равенством спроса и предложения...

Кардиналистский и ординалистский подходы Кардиналистский (количественный подход) к анализу полезности основан на представлении о возможности измерения различных благ в условных единицах полезности...

Обзор компонентов Multisim Компоненты – это основа любой схемы, это все элементы, из которых она состоит. Multisim оперирует с двумя категориями...

Общая и профессиональная культура педагога: сущность, специфика, взаимосвязь Педагогическая культура- часть общечеловеческих культуры, в которой запечатлил духовные и материальные ценности образования и воспитания, осуществляя образовательно-воспитательный процесс...

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

Ведение учета результатов боевой подготовки в роте и во взводе Содержание журнала учета боевой подготовки во взводе. Учет результатов боевой подготовки - есть отражение количественных и качественных показателей выполнения планов подготовки соединений...

Способы тактических действий при проведении специальных операций Специальные операции проводятся с применением следующих основных тактических способов действий: охрана...

Искусство подбора персонала. Как оценить человека за час Искусство подбора персонала. Как оценить человека за час...

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

Studopedia.info - Студопедия - 2014-2024 год . (0.012 сек.) русская версия | украинская версия