Размерные и ссылочные типы
Все типы в PascalABC.NET подразделяются на две большие группы: размерные и ссылочные. К размерным относятся все простые типы, указатели, записи, статические массивы, множества и строки. К ссылочным типам относятся классы, динамические массивы, файлы и процедурный тип.
Размерные типы более эффективны при вычислениях: они занимают меньше памяти и операции, выполняемые над небольшими размерными типами, максимально эффективны. Ссылочные типы обладают большей гибкостью: память под них выделяется динамически в процессе работы программы и освобождается автоматически, когда объект ссылочного типа перестаёт использоваться.
Выделение памяти
Память под переменную размерного типа распределяется на программном стеке в момент её описания. При этом переменная размерного типа хранит значение этого типа.
var i: integer; // здесь под i выделяется память
i := 5;
Переменная ссылочного типа представляет собой ссылку на объект некоторого класса в динамической памяти. Если она не инициализирована, то хранит специальное значение nil (нулевая ссылка). Для инициализации ссылочных переменных используется вызов конструктора соответствующего класса:
type Person = auto class
name: string;
age: integer;
end;
var p: Person; // p хранит значение nil, память под объект не выделена
p := new Person('Иванов',20); // конструктор выделяет память под объект
Присваивание
При присваивании переменных размерного типа копируются значения этого типа. Если размерный тип имеет большой размер, эта операция может выполняться долго. Например:
var a,a1: array [1..1000000] of integer;
a1 := a; // копируются все 1000000 элементов
При присваивании переменных ссылочного типа осуществляется присваивание ссылок, в итоге после присваивания обе ссылки ссылаются на один объект в динамической памяти:
var p1: Person;
p1 := p; // копируется ссылка
Сравнение на равенство
Сравнение на равенство объектов размерного типа сравнивает их значения. В частности, две переменные типа запись равны если равны все поля этих записей.
type PersonRec = record
name: string;
age: integer;
end;
var p,p1: PersonRec;
p.name := 'Иванов'; p.age := 20;
p1.name := 'Иванов'; p1.age := 20;
writeln(p1=p); // True
При сравнении на равенство переменных ссылочного типа проверяется, что они ссылаются на один и тот же объект.
var p := new Person('Иванов',20);
var p1 := new Person('Иванов',20);
writeln(p1=p); // False
Управление памятью
Размерные типы распределяются на программном стеке, поэтому не нуждаются в специальном управлении памятью. Под глобальные размерные переменные память распределена всё время работы программы. Под локальные размерные переменные память выделяется в момент вызова подпрограммы. а освобождается в момент завершения работы этой подпрограммы.
Управление памятью для ссылочных типов осуществляется автоматически сборщиком мусора. Сборщик мусора запускается в неопределенный момент времени когда управляемой памяти перестаёт хватать. Он возвращает в пул неиспользуемой памяти те объекты, на которые больше никто не ссылается, после чего дефрагментирует оставшуюся память, в результате чего динамическая память всегда дефрагментирована и ее выделение при вызове конструктора происходит практически мгновенно.
Передача в подпрограммы
При передаче размерных типов по значению происходит копирование значения фактического параметра в переменную-формальный параметр. Если размерный тип имеет большой размер, это может занимать продолжительное время, поэтому размерный тип в этом случае передаётся по ссылке на константу:
type Arr = array [1..100] of integer;
procedure PrintArray(const a: Arr; n: integer);
begin
for var i:=1 to n do
Print(a[i])
end;
Ссылочные типы передаются в подпрограмму, как правило, по значению. При передаче таких параметров происходит копирование ссылки, в результате формальный и фактический параметр будут ссылаться на один объект.
procedure Change666(a: array of integer);
begin
a[0] := 666;
end;
При этом в результате изменения формального параметра внутри подпрограммы меняется и содержимое соответствующего фактического параметра при вызове подпрограммы.