Шаг 71.
Создание и уничтожение динамических переменных

    На этом шаге мы рассмотрим вопросы, связанные с созданием и уничтожением динамических переменных.

Процедура New
Функции MaxAvail, SizeOf
Функция MemAvail
Процедура Dispose


    Основные действия над динамическими переменными - создание и уничтожение - реализуются в языке программирования Pascal стандартными процедурами New и Dispose.

    Процедура New предназначена для создания динамических переменных определенного типа или для отведения памяти в куче для хранения значений динамической переменной. Единственным параметром процедуры New является переменная ссылочного типа:


     New (<переменная ссылочного типа>);             . 

    Процедура действует следующим образом:

    Следующий фрагмент программы:


   .     .      .
     Var
       P : ^Integer;
     begin
        New (P);
   .    .      .

приведет к отведению в куче области памяти, достаточной для хранения значения переменной целого типа (2 байта) и присваиванию указателя на эту область переменной Р. После этого доступ к созданной динамической переменной возможен только через указатель Р: P^:=2;.

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


   .    .      .
     Var
       P : ^Integer;
     begin
     P := New(^Integer);
   .    .      .

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

    Например, если необходимо создать динамическую переменную типа LongInt, то можно предложить следующую технику отведения памяти:


     .     .     .
       PL: ^LongInt;
     begin
       if MaxAvail >= 4 then  New (PL)
       else   WriteLen ('Исчерпана динамическая память');
     .     .     .

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


      .     .     .
       PL: ^LongInt;
     begin
       if MaxAvail >= SizeOf(LongInt) then  New (PL)
       else   WriteLen ('Исчерпана динамическая память');
     .     .     .

    Кроме функции MaxAvail в языке программирования Pascal имеется функция MemAvail, которая возвращает суммарный размер всех свободных областей динамической памяти. В общем случае эти две функции дают разные результаты. Дело в том, что из-за произвольного характера отведения и освобождения памяти куча может представлять собой случайную последовательность свободных и занятых областей различных размеров. Функция MaxAvail определяет наибольшую свободную область, функция MemAvail - общий объем свободных областей.

    Для освобождения памяти, отведенной с помощью процедуры или функции New, используется стандартная процедура Dispose. Параметрам этой процедуры должен быть указатель на динамическую переменную, причем эта переменная должна быть ранее размещена в куче посредством процедуры или функции New; при этом тип размещенной переменной должен совпадать с базовым типом параметра процедуры Dispose, например:


     Var
       P : ^Integer;
     Begin
          New (P);
          < Действия с указателем Р>
          Dispose (P);
     End.

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

    Следующий шаг посвящен описанию механизма управления динамической памятью.


Процедура New Функции MaxAvail, SizeOf Функция MemAvail Процедура Dispose

Предыдущий шаг Содержание Следующий шаг