Главная | Обратная связь | Поможем написать вашу работу!
МегаЛекции

Высвобождение памяти с помощью оператора Dispose




Использование оператора new для запроса памяти представляет собой наиболее эффектную сторону механизма управления памятью. Другой стороной является оператор dispose, который позволяет высвободить память ("вернуть" в общую область) после того, как ее использование завершено. Это — важный шаг к наиболее эффективному использованию памяти. Память, которая возвращается, или высвобождается, может быть повторно использована другими модулями программы.

Var

ps: ^Integer;

Begin

New(ps); //выделение области памяти для значений типа Integer

...

Dispose(ps); //освобождаем память

В этом примере очищается область памяти, на которую указывает ps, но сам указатель ps не удаляется. Его можно использовать повторно, например, для указания на другую выделенную область памяти. Операторы new и dispose всегда необходимо применять сбалансирование, иначе может произойти утечка памяти; другими словами, наступит момент, когда выделенную память нельзя будет больше использовать. Если утечка памяти чересчур велика, она может привести к останову программы при поиске дополнительной памяти.

Не следует пытаться повторно очистить блок памяти, который уже высвобожден. Результат такого действия не определен. Нельзя также использовать оператор dispose для освобождения памяти, созданной при объявлении переменных:

Var

ps: ^Integer;

pi: ^Integer;

jugs: Integer;

Begin

New(ps); //допустимо

Dispose(ps); //допустимо

Dispose(ps); //уже недопустимо

jugs:= 5; //допустимо

pi:= @jugs; //допустимо

Dispose(pi); //недопустимо, память не выделена оператором new

Отметим, что важным залогом корректности работы оператора dispose является то, что он должен применяться по отношению к области памяти, выделенной с помощью оператора new. Это не значит, что нужно использовать тот же указатель, что и для new; важно, чтобы это был тот же самый адрес:

Var

ps, pq: ^Integer;

Begin

New(ps); //распределение памяти

pq:= ps; //второму указателю присваивается адрес того же самого блока памяти

Dispose(pq); //применение оператора dispose со вторым указателем

Использование оператора New для создания динамических структур

Если требуется выделять область памяти только для такого количества структур, которое необходимо программе в определенный момент, снова приходит на помощь оператор New. Он позволяет создавать динамические структуры. Опять же, слово "динамические" означает то, что память выделяется во время выполнения программы, а не во время компиляции. Кроме того, рассмотренная выше техника работы со структурами применима к классам, так как классы во многом похожи на структуры.

Использование оператора New при работе со структурами происходит в два этапа: создание структуры и доступ к ее элементам. Например, создать безымянную структуру типа TInflatable и присвоить ее адрес подходящему указателю можно следующим образом:

Var

ps: ^TInflatable;

Begin

New(ps);

Здесь указателю ps присваивается адрес части свободной памяти, достаточной для хранения структуры типа TInflatable.

Получить доступ к элементам структуры сложнее. Например, если ps указывает на структуру типа
TInflatable, то ps^.price — это элемент price указанной структуры.

Программа 3_8

// использование оператора new для создания структуры

program Project1;

 

{$APPTYPE CONSOLE}

 

Uses

SysUtils;

Type

TInflatable = record //шаблон структуры

name: String[20];

volume: Real;

price: Real;

end;

Var

ps: ^TInflatable;

 

Begin

New(ps); //выделение области памяти для структуры

Write('Enter name of inflatable item: ');

Readln(ps^.name);

Write('Enter volume in cubic feet: ');

Readln(ps^.volume);

Write('Enter price: $');

Readln(ps^.price);

Writeln('Name: ', ps^.name);

Writeln('Volume: ', ps^.volume:1:2);

Writeln('Price: ', ps^.price:1:2);

Dispose(ps);

 

Readln;

end.

Результат:

Enter name of inflatable item: Fabulous Frodo

Enter volume in cubic feet: 1.4

Enter price: $ 17.99

Name: Fabulous Frodo

Volume: 1.40

Price: $17.99

Динамический массив

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

Объявление динамического массива содержит только его имя и тип элементов — один из базовых типов. Синтаксис объявления:

<имя> array of <базовый тип>

Например

var A: array of integer;

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

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

SetLength(А, 10);

выделяет для массива А место в памяти под 10 элементов и задает нулевые значения всех элементов.

Индексы динамического массива — всегда целые числа, начинающиеся с 0.

Таким образом, в приведенном примере массив содержит элементы от А[0] до А[9].

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

Var

A: array of integer;

N,i: integer;

Begin

N:=5;

SetLength(A,N); //массив А(0,0,0,0,0)

for i:=0 to N-1 do

A[i]:=i+1; // массив А(1,2,3,4,5)

N:=7;

SetLength(A, N); // массив A(1,2,3, 4, 5, 0, 0)

N:=3;

SetLength(A/N); // массив А(1,2,3)

N:=4;

SetLength(A,N); // массив A(1,2,3,0)

end;

Впрочем, усечение динамического массива лучше проводить функцией Сору, присваивая ее результат самому массиву. Например, оператор

А:= Сору(А, 0, 3);

усекает динамический массив А, оставляя неизменными первые три его элемента.

Если динамический массив уже размещен в памяти, к переменной этого массива можно применять стандартные для массивов функции Length — длина, High — наибольшее значение индекса (очевидно, что всегда
High = Length -1) и Low — наименьшее значение индекса (всегда 0). Если массив имеет нулевую длину, то High возвращает -1, т.е. при этом получается, что High < Low.

Сама переменная динамического массива является указателем на начало массива. Если место под массив еще не выделено, значение переменной равно nil. Но это не совсем обычный указатель. Его нельзя разыменовывать операцией ^, нельзя передать в процедуры New и Dispose.

Удалить из памяти динамический массив можно одним из следующих способов: присвоить ему значение nil, или установить нулевую длину. Таким образом, эквивалентны следующие операторы:

А:= nil;

или

SetLength(А,0);

Программа 3_9

program Project1;

 

{$APPTYPE CONSOLE}

 

Uses

SysUtils;

Var

A: array of Integer;

 

Begin

SetLength(A, 1);

A[0]:= 2;

Writeln(A[0]);

SetLength(A, 2);

A[1]:= 5;

Writeln(A[0], ' ', A[1]);

Readln;

end.

Результат:

2 5

ВОПРОСЫ ДЛЯ ПОВТОРЕНИЯ (3)

1. Как бы вы объявили следующие объекты данных?

a. actors — массив 30 элементов типа String.

b. betsie — массив 100 элементов типа Smallint.

c. chuck — массив 13 элементов типа Real.

d. dipsea — массив 64 элементов типа Extended.

2. Объявите массив из пяти элементов типа Integer и заполните его первыми пятью целыми нечетными числами.

3. Сконструируйте оператор, который присваивает сумму первого и последнего элемента массива из вопроса 2 переменной even.

4. Сконструируйте оператор, который выводит значение второго элемента массива ideas типа Real.

5. Объявите строку типа String и присвойте ему значение строки "cheeseburger".

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

7. Объявите переменную типа, описанного в вопросе 6, и присвойте ей начальное значение.

8. Предположим, что переменная ted имеет тип Real. Объявите указатель на ted и используйте его для вывода значения этой переменной.

9. Создайте фрагмент кода, который запрашивает ввод с клавиатуру положительных целых чисел, а затем создает динамический массив из полученного количества значений типа Integer.

10. Напишите фрагмент кода, который динамически определяет запись типа, описанного в вопросе 6, а затем считывает значение для элемента этой записи, описывающего вид.

Поделиться:





Воспользуйтесь поиском по сайту:



©2015 - 2024 megalektsii.ru Все авторские права принадлежат авторам лекционных материалов. Обратная связь с нами...