FreeAndNil и зачем он нужен
Каждый объект в Delphi имеет свой жизненный цикл.
Обычно он сводится к:
Каждый объект в Delphi имеет свой жизненный цикл.
Обычно он сводится к:
- созданию объекта
- манипуляциям с объектом
- удалению объекта
Например выражение MyList: TList; объявляет указатель с именем MyList - это все равно что мы бы написали MyList: Pointer;, с тем лишь отличием, что в первом случае указатель будет типизированным.
Эти объявленные указатели могут использоваться повторно:
MyList := TList.Create;
...
MyList.Free;
MyList := TList.Create;
...
MyList.Free;
в данном случае значение указателя MyList изменяется 2 раза при присвоении MyList := TList.Create;, при этом второй раз значение указателя заменяется на новое.
Знаменитый Access Violation (AV | EAccessViolation)
После второго вызова MyList.Free; указатель MyList не изменяется и указывает на "освобожденный" блок памяти. Отсюда растут ноги знаменитого Access Violation (AV | EAccessViolation). Если после MyList.Free; обратиться к полю, свойству или методу класса TList через указатель MyList, например c := MyList.Count;, мы получим эту распространенную ошибку.
Free vs FreeAndNil или освобождение объектов
Итак мы разобрались с переменными-указателями на объекты. Давайте рассмотрим освобождение объектов. Для освобождения в Delphi предусмотрено 2 стандартных механизма:
- метод Free класса TObject
- процедура FreeAndNil из модуля SysUtils
procedure TObject.Free;
begin
if Self <> nil then
Destroy;
end;
Все что делает данные метод - вызывает стандартный деструктор Destroy при условии что указатель на объект не равен nil
отсюда получаем ошибку AV при попытке повторного освобождения объекта если писать так, например:
MyList := TList.Create;
...
MyList.Free;//указатель на объект не очищается
MyList.Count;//AV - пытались вызвать метод освобожденного объекта
Рассмотрим процедуру FreeAndNil:
procedure FreeAndNil(var Obj);
var
Temp: TObject;
begin
Temp := TObject(Obj);//сохраняем временный указатель на объект
Pointer(Obj) := nil;//очищаем указатель
Temp.Free;//освобождаем объект
end;
Наш пример с "двойным" освобождением завершится без ошибок
MyList := TList.Create;
...
FreeAndNil(MyList);//указатель на объект очищается
FreeAndNil(MyList);//срабатывает проверка на self<>nil в TObject.Free; в procedure FreeAndNil(var Obj);
Машинный код для TObject.Free составляет 12 байт это 6 строк ассемблерного псевдокода
для FreeAndNil - 35 байт или 16 строк ассемблерного псевдокода (из них 5 байт или одна строчка кода - вызов той же TObject.Free) оверхэд составляет 30 байт =) или 10 строк
Что дает оверхэд - очистка указателя при чем до вызова TObject.Free.
Комментариев нет:
Отправить комментарий