Механизм подсчета ссылок

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

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

var Intf, Copy: IInterface;begin ... Copy := Intf; // Copy._Release; Intf._AddRef; Intf := nil; // Intf._Release; end; // Copy._Release

Стандартная реализация методов _AddRef и _Release находится в классе TInterfacedObject. Она достаточно проста и вы легко разберетесь с ней, читая комментарии в исходном тексте.

type TInterfacedObject = class(TObject, IInterface) ... FRefCount: Integer; // Счетчик ссылок function _AddRef: Integer; stdcall; function _Release: Integer; stdcall; ... end; function TInterfacedObject._AddRef: Integer;begin Result := InterlockedIncrement(FRefCount); // Увеличение счетчика ссылокend; function TInterfacedObject._Release: Integer;begin Result := InterlockedDecrement(FRefCount); // Уменьшение счетчика ссылок if Result = 0 then // Если ссылок больше нет, то Destroy; // уничтожение объектаend;

Заметим, что функции InterlockedIncrement и InterlockedDecrement просто увеличивают значение целочисленной переменной на единицу. В отличие от обычного оператора сложения, они обеспечивают атомарное изменение значения переменной, что очень важно для правильной работы распараллеленных (многопоточных) программ.

Приведенную выше реализацию методов _AddRef и _Release автоматически получают все наследники класса TInterfacedObject, в том числе и классы TTextReader, TDelimitedReader и TFixedReader. Поэтому неиспользуемые объекты классов TDelimitedReader и TFixedReader тоже автоматически уничтожаются при работе с ними через интерфейсные переменные:

var Obj: TDelimitedReader; Intf, Copy: ITextReader;begin Obj := TDelimitedReader.Create('MyData.del', ';'); Intf := Obj; // Obj._AddRef -> Obj.FRefCount = 1 Copy := Intf; // Obj._AddRef -> Obj.FRefCount = 2 ... Intf := nil; // Obj._Release -> Obj.FRefCount = 1 Copy := nil; // Obj._Release -> Obj.FRefCount = 0 -> Obj.Destroy Obj.Free; // Ошибка! Объект уже уничтожен и переменная Obj указывает в никудаend;

Обратите внимание, что объектные переменные не учитываются при подсчете ссылок. Поэтому мы настоятельно рекомендуем избегать смешивания интерфейсных и объектных переменных. Если вы планируете использовать объект через интерфейс, то лучше всего результат работы конструктора сразу присвоить интерфейсной переменной:

var Intf: ITextReader;begin Intf := TDelimitedReader.Create('MyData.del', ';'); // FRefCount = 1 ... Intf := nil; // FRefCount = 0 -> Destroyend;

Если интерфейс является входным параметром подпрограммы, то при вызове подпрограммы создается копия интерфейсной переменной с вызовом метода _AddRef:

procedure LoadItems(R: ITextReader);begin...end; var Reader: ITextReader;begin ... LoadItems(Reader); // Создается копия переменной Reader и вызывается Reader._AddRefend;

Копия не создается, если входной параметр описан с ключевым словом const:

procedure LoadItems(const R: ITextReader);begin...end; var Reader: ITextRedaer;begin ... LoadItems(Reader); // Копия не создается, метод _AddRef не вызывается end;

Интерфейсная переменная уничтожается при выходе из области действия переменной, а это значит, что у нее автоматически вызывается метод _Release:

var Intf: ITextRedaer;begin Intf := TDelimitedReader.Create('MyData.del', ';'); ...end; // Intf._Release







Дата добавления: 2016-02-09; просмотров: 576;


Поиск по сайту:

При помощи поиска вы сможете найти нужную вам информацию.

Поделитесь с друзьями:

Если вам перенёс пользу информационный материал, или помог в учебе – поделитесь этим сайтом с друзьями и знакомыми.
helpiks.org - Хелпикс.Орг - 2014-2024 год. Материал сайта представляется для ознакомительного и учебного использования. | Поддержка
Генерация страницы за: 0.007 сек.