Читайте также:
|
|
Механизм подсчета ссылок на объект предназначен для автоматического уничтожения неиспользуемых объектов. Неиспользуемым считается объект, на который не ссылается ни одна интерфейсная переменная. Подсчет ссылок на объект обеспечивают методы _ 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 просто увеличивают значение целочисленной переменной на единицу. В отличие от обычного оператора сложения, они обеспечивают атомарное изменение значения переменной, что очень важно для правильной работы многопоточных программ.
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 -> Destroy
End;
Если интерфейс является входным параметром подпрограммы, то при вызове подпрограммы
создается копия интерфейсной переменной с вызовом метода _ AddRef:
procedure LoadItems(R: ITextReader);
Var
Reader: ITextReader;
Begin
LoadItems(Reader); // Создается копия переменной Reader и вызывается
Дата добавления: 2015-11-16; просмотров: 58 | Нарушение авторских прав
<== предыдущая страница | | | следующая страница ==> |
Описание интерфейса | | | Reader._AddRef |