Текущий архив: 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.48 MB
Время: 0.012 c