Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2003.03.27;
Скачать: CL | DM;

Вниз

Запутался с интерфейснымми ссылками   Найти похожие ветки 

 
oomneeq ©   (2003-03-13 14:31) [0]

имеем

type
IMyInterface=interface
end;

TMyComp=class(TComponent,IMyInterface)
end;

TMyForm=class(TForm)
private
FILink: IMyInterface
public
// constructor Create(AOwner:TComponent);
end;

procedure Test;
var MF:TMyForm;
begin
MF:=TMyForm.Create(nil);
with MF do begin
FILink:=TMyComp.Create(MF);
Showmodal;
//block1
//надо ли тут чтото делать с FILink
//например FILink:=nil;
//по идее, объект, созданный с помощью FILink
//будет уничтожен самой формой-владельцем (MF)
Free;
end; // with
//block2
//а вот тут, при выходе, я предполагаю, что дельфи делает попытку
//очистить FILink как любую интерфейсную ссылку.
//но объект то уже уничтожен, и случается AV (через раз)
//в System._IntfClear
end;

end;


_Addref и _Release не переопределены, т.е. испльзуются
TComponent"ские методы, возврщающие в данном случае -1 всегда

Действительно ли мое предположение по поводу Block2
и надо ли садить на nil FILink в Block1 ??
Научите плиз, мастера, как грамотно здесь поступать


 
oomneeq ©   (2003-03-13 14:44) [1]

Я тут немного подумал, и решил уточнить вопрос;
cчитается ли выход из процедуры Test выходом и з области видимости для переменной FILink?
Ведь это не локальная переменная, а поле уже уничтоженногоо
объекта!


 
Smithson ©   (2003-03-13 14:54) [2]

Где-то я читал, что IUnknow по умолчанию в VCL не реализован. То бишь тебе надо их делать.


 
viajero   (2003-03-13 15:35) [3]

TComponent действительно имеет весьма специфическую реализацию
IUnknow:


function TComponent.QueryInterface(const IID: TGUID; out Obj): HResult;
begin
if FVCLComObject = nil then
begin
if GetInterface(IID, Obj) then Result := S_OK
else Result := E_NOINTERFACE
end
else
Result := IVCLComObject(FVCLComObject).QueryInterface(IID, Obj);
end;

function TComponent._AddRef: Integer;
begin
if FVCLComObject = nil then
Result := -1 // -1 indicates no reference counting is taking place
else
Result := IVCLComObject(FVCLComObject)._AddRef;
end;

function TComponent._Release: Integer;
begin
if FVCLComObject = nil then
Result := -1 // -1 indicates no reference counting is taking place
else
Result := IVCLComObject(FVCLComObject)._Release;
end;


Если ты хочешь иметь стандартное поведение интерфейса,
тебе придётся переопределить_Addref и _Release, а так же QueryInterface a la TInterfacedObject.


 
viajero   (2003-03-13 15:36) [4]

Пардон, QueryInterface менять не надо


 
vedmed ©   (2003-03-13 16:14) [5]

При выходе из процедуры в block2 вызывается метод _Release уже не существующего объекта, отсюда и AV. Присвоение nil в block1 в данном случае должно решить проблему, т. к. вызов _Release для объектов равных nil не производиться.


 
icWasya ©   (2003-03-13 16:35) [6]


> vedmed © (13.03.03 16:14)
> При выходе из процедуры в block2 вызывается метод _Release
> уже не существующего объекта, отсюда и AV. Присвоение nil
> в block1 в данном случае должно решить проблему, т. к. вызов
> _Release для объектов равных nil не производиться.

ничего не вызывается, поскольку область видимости
FILink - весь объект TMyForm
, и FILink будет уничтожен только в деструкторе TMyForm


 
REA ©   (2003-03-13 16:46) [7]

ИМХО проще перегрузить и оттрассировать откуда что вызывается, но по логике форма удаляет объект, а счетчик ссылок не используется.


 
vedmed ©   (2003-03-13 16:56) [8]

2 icWasya
действительно, не заметил 8-(


 
oomneeq ©   (2003-03-13 17:23) [9]

>Smithson © (13.03.03 14:54)
>Где-то я читал, что IUnknow по умолчанию в VCL не реализован. То бишь тебе надо их делать.
Кого "их"?
IUnknow не реализован, но все к этому подготовлено, т.е. все три метода реализованы, viajero их тут нарисовал.

Я тут погонял тест.
Похоже дело еще круче.

>icWasya © (13.03.03 16:35)
>ничего не вызывается, поскольку область видимости
>FILink - весь объект TMyForm
похоже на то, т.к. AV cлучается до входа в block2 - т.е. во Free.
(я дописал выполняемую строчку сразу за Free и поставил брекпойнт на нее) так вот - AV случается не доходя до этой точки

Вопрос теперь такой:
если область видимости FILink - весь объект TMyForm то
что в таком случае считается выходом из зоны. точнее сказать в какой момент вызывается уборщик? При выходе из TObject.Destroy ?

Я предполагаю, что как минимум после освобождения всех подчиненных компонентов - один из которых создан с помощью FILink

т.е. когда доходит дело чистить FILink, то форма-владелец у же грохнула всех владеемых и компонент, на который переменная FILink все еще указывает, уже уничтожен, но чистку уже не остановить, вот и AV.

Ну вот, сам себе все и рассказал.

Опровержения и подтверждения принимаются.

Что происходит раньше при уничтожении формы - освобождение всех подчиненных компонентов или очистка интерфейсных ссылок




 
icWasya ©   (2003-03-13 18:07) [10]


> Что происходит раньше при уничтожении формы - освобождение
> всех подчиненных компонентов или очистка интерфейсных ссылок


очистка интерфейсных ссылок скорее всего происходит в TObject.Destroy,
освобождение всех подчиненных компонентов происходит раньше - в TComponent.Destroy




 
icWasya ©   (2003-03-13 18:13) [11]

а вообще говоря не рекомендуется смешивать работу через интерфейсы и через компоненты


 
REA ©   (2003-03-13 18:21) [12]

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


 
Serginio   (2003-03-13 18:23) [13]

Сделай
TMyForm=class(TForm,IMyInterface)
private
public
// constructor Create(AOwner:TComponent);
end;
TMyForm.Create(nil) As IMyInterface;




 
vuk ©   (2003-03-13 18:24) [14]

>что в таком случае считается выходом из зоны.
Разрушение экземпляра. см. в system: _ClassDestroy, TObject.FreeInstance, TObject.CleanupInstance

>Что происходит раньше при уничтожении формы - освобождение всех
>подчиненных компонентов или очистка интерфейсных ссылок
Сначала происходит удаление компонентов. Финализация делается в самую последнюю очередь.

В принципе решить Вашу проблему можно несколькими способами:
1. Принудительно очистить FILink в Test
2. Если в TMyComp перекрыты _AddRef и _Release, так, что подстчет ссылок всё-таки делается, то можно не делать форму владельцем экземпляра компонента.


 
oomneeq ©   (2003-03-13 18:59) [15]

Радует ваша отзывчивость. Спасибо всем.
>icWasya © (13.03.03 18:13)
а вообще говоря не рекомендуется смешивать работу через интерфейсы и через компоненты

Да вообще я про это читал. Только наверно не врубаюсь.
Ты не мог бы сказать, где конкретно в вышеуказанном примере
происходит смешивание?

и еще к тому же - правильно ли я мыслю, что смешивание (допустим я разобрался что это такое :-) ) чревато боком только в случаях когда подсчет ссылок реализован, и безопасно, если не реализован.

>Serginio (13.03.03 18:23)
Ваще не понял, о чем ты. В примере интерфейс реализует ведь не форма, а TMyComp ?!

2vuk
>1. Принудительно очистить FILink в Test
cпасибо, я как раз так и делаю, просто теперь уже осознанно :=)

>2. Если в TMyComp перекрыты _AddRef и _Release, так, что подстчет ссылок всё-таки делается, то можно не делать форму владельцем экземпляра компонента

Сдается мне, что если не делать форму владельцем, и перекрыты
_AddRef и _Release, так, что подстчет ссылок всё-таки делается,
то FILink:=nil не только обнулит указатель, но еще и уничтожит объект, как это и заведено у интерфейсных ссылок.
т.е. получается по любому FILink:=nil есть благо в случаях сомнения.




 
vuk ©   (2003-03-13 19:19) [16]

>т.е. получается по любому FILink:=nil есть благо в случаях
>сомнения.
Ну... В одном случае это необходимо, а в другом используется просто как "контрольный в голову".


 
Serginio   (2003-03-13 19:21) [17]

У тебя сначала уничтожается TMyComp
а ссылка в TMyForm остается.
делай в TMyComp.Destroy
(Owner as TMyForm).ILink:=nil;


 
icWasya ©   (2003-03-13 19:37) [18]

>где конкретно в вышеуказанном примере
происходит смешивание?
когда работаешь с TMyForm как с компонетом -

TMyForm.Create(Self)

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


 
Serginio   (2003-03-13 19:38) [19]

Вернее в TMyForm.Destroy
FILink:=nil;
inherited Destroy;


 
oomneeq ©   (2003-03-13 19:55) [20]

>icWasya © (13.03.03 19:37)
Ок, проясняется. Применительно к примеру, потенциальные грабли в том, что созданый через интерфейсную ссылку объект включается в список Сomponents, каждый элемент которого подлежащит явному уничтожению (читай-явному вызову Destroy) что не есть логично для таким образом создаваемых объектов.

Ну вот, день не зря прошел....:)




Страницы: 1 вся ветка

Текущий архив: 2003.03.27;
Скачать: CL | DM;

Наверх




Память: 0.53 MB
Время: 0.015 c
3-87836
WoWa
2003-03-10 16:33
2003.03.27
ADO


3-87878
ddenisv
2003-03-11 13:24
2003.03.27
DBGridEh - как делать следующее?


8-88096
sergn
2002-12-19 21:12
2003.03.27
Вывод текста с обводкой букв.


14-88237
AlLive
2003-03-05 02:07
2003.03.27
Прием отправка e-mail средствами Delphi 6


1-88039
seledka
2003-03-14 16:17
2003.03.27
файлы и директории