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

Вниз

Ошибка после удаления интерфейса   Найти похожие ветки 

 
Семен Сорокин ©   (2005-05-18 17:36) [0]

Приветствую, пол дня бьюсь над одной проблемой:

имеется следующее описание:

unit Unit1;

interface

uses
 Classes;

type
 TNoRefrencedObject = class(TObject)
 protected
   function QueryInterface(const IID: TGUID; out Obj): HResult; virtual; stdcall;
   function _AddRef: Integer; stdcall;
   function _Release: Integer; stdcall;
 end;

 TBaseListClass = class(TNoRefrencedObject, IUnknown)
 private
   FItems: TStrings;
 public
   constructor Create;
   destructor Destroy; override;
 end;

 IInterface1 = interface
 ["{7C9DD5BE-DCE3-4A5B-889C-EF3CD7A754DC}"]
   function GetData: integer;
 end;

 TClass1 = class(TNoRefrencedObject, IInterface1)
 private
   FData: integer;
 public
   function GetData: integer;
 end;

 IInterface2 = interface
 ["{B1E31834-213D-4519-AC3B-5A5C278006B6}"]
   function GetInterface1(AIndex: integer): IInterface1;
 end;

 TClass2 = class(TBaseListClass, IInterface2)
 public
   function GetInterface1(AIndex: integer): IInterface1;
   destructor Destroy; override;
 end;

 IInterface3 = interface
 ["{3FB223AB-8EA5-46CB-B3F1-AB3CF5698F8B}"]
   function GetInterface2: IInterface2;
 end;

 TClass3 = class(TInterfacedObject, IInterface3)
 private
   FClass2: TClass2;
 public
   function GetInterface2: IInterface2;
   constructor Create;
   destructor Destroy; override;
 end;

implementation

{ TNoRefrencedObject }

function TNoRefrencedObject._AddRef: Integer;
begin
Result := -1
end;

function TNoRefrencedObject._Release: Integer;
begin
Result := -1
end;

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

{ TBaseListClass }

constructor TBaseListClass.Create;
begin
FItems := TStringList.Create;
end;

destructor TBaseListClass.Destroy;
begin
FItems.Free;
inherited;
end;

{ TClass1 }

function TClass1.GetData: integer;
begin
Result := FData
end;

{ TClass2 }

destructor TClass2.Destroy;
begin
 TClass1(FItems.Objects[0]).Free;
 inherited;
end;

function TClass2.GetInterface1(AIndex: integer): IInterface1;
begin
Result := TClass1(FItems.Objects[AIndex])
end;

{ TClass3 }

constructor TClass3.Create;
var
 cl1: TClass1;
begin
FClass2 := TClass2.Create;
cl1 := TClass1.Create;
cl1.FData := 555;
FClass2.FItems.AddObject("xxx", cl1)
end;

destructor TClass3.Destroy;
begin
FClass2.Free;
inherited Destroy;
end;

function TClass3.GetInterface2: IInterface2;
begin
Result := FClass2
end;

end.


и сам проект:

program Project1;
uses
 SysUtils,
 Unit1 in "Unit1.pas";

var
 _main: IInterface3;
 _int1: IInterface1;
 _data: integer;
begin
_main := TClass3.Create;
// если закоментарить следующую строку, то ошибки не будет
_int1 := _main.GetInterface2.GetInterface1(0);  
_int1 := nil;
_main := nil
end.


После выполнения кода (после убийства _main) происходит AV.
Подскажите где я не прав.


 
Иван Шихалев ©   (2005-05-18 17:47) [1]

После _int1 := nil, объект освобождается, поскольку _Release = -1


 
Иван Шихалев ©   (2005-05-18 17:49) [2]

Хотя... сорри, гоню


 
Семен Сорокин ©   (2005-05-18 17:53) [3]

если закоментарить строку
TClass1(FItems.Objects[0]).Free;
в деструкторе TClass2 то AV не возникает, но, имхо, тогда будет утечка памяти.

После _int1 := nil, объект не освобождается т.к. он унаследован от TNoRefrencedObject.


 
Shaman_Naydak;   (2005-05-18 19:35) [4]

Создается неявная переменная из-за _main.GetInterface2
И освобождаться она будет.. когда?.. прально.. уже на выходе из метода, когда объект тю-тю..
отсюда мораль.. смешивать подсчитываемые ссылки и неподситываемые не самая лучшая затея


 
Семен Сорокин ©   (2005-05-19 09:57) [5]


> Shaman_Naydak;   (18.05.05 19:35) [4]
> Создается неявная переменная из-за _main.GetInterface2
> И освобождаться она будет.. когда?.. прально.. уже на выходе
> из метода, когда объект тю-тю..


а здесь Вы не правы, потому как _main.GetInterface2 - возвращает неподсчитываемый интерфейс, вот код - ошибка та же:

var
 _main: IInterface3;
 _int1: IInterface1;
 _int2: IInterface2;
 _data: integer;
begin
 _main := TClass3.Create;
 _int2 := _main.GetInterface2;
 _int1 := _int2.GetInterface1(0);
 _data := _int1.GetData;
 _int1 := nil;
 _int2 := nil;
 _main := nil
end.



> отсюда мораль.. смешивать подсчитываемые ссылки и неподситываемые
> не самая лучшая затея

в даннолм случе с подсчитываемыми ссылками у сменяя только главный (IInterface3) интерфейс.

ЗЫ. Проблема осталась :(


 
Slym ©   (2005-05-19 11:03) [6]

TClass - Это указатель на объект
IInterface - Это указатель на указатель объекта!!!


 
Семен Сорокин ©   (2005-05-19 11:33) [7]


> Slym ©   (19.05.05 11:03) [6]
> TClass - Это указатель на объект
> IInterface - Это указатель на указатель объекта!!!

Что Вы хотите этим сказать?
TClass - это указатель на тип объекта, а IInterface - указатель на тип интерфейса


 
Shaman_Naydak;   (2005-05-19 17:51) [8]

Молодой человек, послушайте старого и мудрого человека...
Все дело в скрытых и неявных переменных!
Когда вы вызываете функцию, возвращающую интерфейс, то у вас
заводится стековая переменная, отвечающая за эту переменную.
А уж затем производится копирование в глобальную переменную, которую вы задали..
Вот если бы вы перенесли весь код в процедуру, а не в главной программе.. то у вас переменные стали бы локальными и у дельфи хватит ума не создавать по второй копии переменной для хранения интерфейса.. Ферштейн?
Другой способ решения вопроса - использование процедур с out параметром... тут тоже не будет стековых переменных...

И наконец.. не читайте до обеда советских газет..
то есть не используйте неразумно неподсчитываемые интерфейсы...!
За сим разрешите откланяться ;))


 
Семен Сорокин ©   (2005-05-19 18:17) [9]


> Shaman_Naydak;   (19.05.05 17:51) [8]

Благодарю, все понятно.


 
Slym ©   (2005-05-20 06:17) [10]


>_main := TClass3.Create;
> _main := nil;

Ты думаешь сдесь нет утечки памяти?... Есть!
Где ты ты вызываешь деструктор? Нигде!
Интерфейсы с подсчетом, сами себе деструктор вызывают когда RefCount=0

Obj (Экземпляр TClass)- Это указатель на объект, т.е. при передачи объекта (как результата функции, или входного параметра) используется указатель на объект.
(@Obj/Obj^)

Interface - Это указатель на указатель объекта, т.е. при передаче (как результата функции, или входного параметра) используется указатель на указаетель объекта.(@@Obj/Obj^^)

Посмотри Демосы QRegister


 
Семен Сорокин ©   (2005-05-20 11:50) [11]


> Slym ©   (20.05.05 06:17) [10]
>
> >_main := TClass3.Create;
> > _main := nil;
>
> Ты думаешь сдесь нет утечки памяти?... Есть!
> Где ты ты вызываешь деструктор? Нигде!
> Интерфейсы с подсчетом, сами себе деструктор вызывают когда
> RefCount=0


Думаю здесь нет :)) даже знаю, потому как
TClass3 = class(TInterfacedObject, IInterface3)

вопрос снят



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

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

Наверх




Память: 0.5 MB
Время: 0.046 c
2-1143106704
tyo
2006-03-23 12:38
2006.04.09
Все открытые формы приложения


1-1141328534
Serafim-ss
2006-03-02 22:42
2006.04.09
Marquee progress bar как в эсплорере


15-1142403938
Emik
2006-03-15 09:25
2006.04.09
FIBPlus Tools


2-1143012937
apl
2006-03-22 10:35
2006.04.09
Select - подскажите


15-1142860078
Freelancer
2006-03-20 16:07
2006.04.09
И снова тема диплома