Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Очередные баги компилятора.


Страницы:   1 2

oxffff ©   (2007-04-09 15:41:00) 

Сегодня рассмотрим const передачу интерфейсов

Простой пример

procedure abc(const a:Iunknown);
var b:Iunknown;
begin
b:=a;
b:=nil;
end;

procedure TForm1.Button1Click(Sender: TObject);
var a:TInterfacedObject;
begin
a:=TInterfacedObject.Create;
abc(a);
// a уже разрушен
end;

Здесь после вызова  abc объект а уже разрушен.

Аналогичный рабочий пример используя временную переменную

procedure TForm1.Button1Click(Sender: TObject);
var a:TInterfacedObject;
begin
a:=TInterfacedObject.Create;
abc(a as IUnknown);
// a еще жив
end;

Здесь после вызова  abc объект a еще неразрушен.

Выводы.

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

Выявленная ошибка работает на D7, BDS 2006 SP2


oxffff   (2007-04-09 16:45:00) [21]


> SlymRO ©   (09.04.07 16:28) [8]
> Джо ©   (09.04.07 16:20) [4]
> abc(a as IUnknown);
> От тута временная переменная (накрутка счетчика)
> abc(a); - так накрутки не происходит, но происходит декрутка
> :) внутри abc
> сей баг аналогичен этому:
> var
>  a:TInterfacedObject;
>  b:IUnknown;
> begin
>  a:=TInterfacedObject.Create;
>  try
>    b:=a as IUnknown;
>    b:=nil;
>  finally
>    a.Free;
>  end;
> end;


Сей пример неудачен. Это не аналогия.


oxffff   (2007-04-09 16:43:00) [22]


> Джо ©   (09.04.07 16:29) [9]
> А, не понял сначала, об чем речь, сорри.


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


oxffff   (2007-04-09 16:37:00) [23]

Вот пример

TSomeClass=class(TinterfacedObject)
protected
SomeText:string;
public
procedure Myproc;virtual;
constructor create;
end;

procedure abc(const a:Iunknown);
var b:Iunknown;
begin
b:=a;
b:=nil;
end;

constructor TSomeClass.create;
begin
inherited;
SomeText:='THIS STRING REFERENCE WILL BE EMPTY AFTER DESTRUCTION';
end;

procedure TSomeClass.Myproc;
begin
showmessage(SomeText);
end;

procedure TForm1.Button1Click(Sender: TObject);
var a:TSomeClass;
begin
a:=TSomeClass.Create;
abc(a);
a.Myproc;
//А После этого уже нет
end;


jack128   (2007-04-09 16:32:00) [24]

ИМХО, это НЕ баг.


Джо   (2007-04-09 16:29:00) [25]

А, не понял сначала, об чем речь, сорри.


SlymRO   (2007-04-09 16:28:00) [26]

Джо ©   (09.04.07 16:20) [4]
abc(a as IUnknown);

От тута временная переменная (накрутка счетчика)
abc(a); - так накрутки не происходит, но происходит декрутка :) внутри abc
сей баг аналогичен этому:
var
 a:TInterfacedObject;
 b:IUnknown;
begin
 a:=TInterfacedObject.Create;
 try
   b:=a as IUnknown;
   b:=nil;
 finally
   a.Free;
 end;
end;


oxffff   (2007-04-09 16:28:00) [27]

Еще раз  

procedure TForm1.Button1Click(Sender: TObject);
var a:TInterfacedObject;
begin
a:=TInterfacedObject.Create;
abc(a);

a.someProc //приведет к сбою в случае если abc работает со счетчиком ссылок. Но это установить нельзя по причине того, что abc может быть произвольной

end;

procedure TForm1.Button1Click(Sender: TObject);
var a:TInterfacedObject;
begin
a:=TInterfacedObject.Create;
abc(a as Inknown);

a.someProc // обработает нормально

end;

Понятно?

Конечно можно сделать так, чтобы гарантировано после abc А был жив

procedure TForm1.Button1Click(Sender: TObject);
var a:TInterfacedObject;
    b:iunknown;
begin
a:=TInterfacedObject.Create;
b:=a;
abc(a);
end;


Но хочеться чтобы это делал компилятор.


oxffff   (2007-04-09 16:23:00) [28]


> Джо ©   (09.04.07 16:20) [4]
> > Здесь после вызова  abc объект a еще неразрушен.
>
>
> type
>  TMyInterfacedObject = class (TInterfacedObject, IUnknown)
>  public
>    destructor Destroy; override;  
>  end;
>
> implementation
>
> { TMyInterfacedObject }
>
> destructor TMyInterfacedObject.Destroy;
> begin
>  ShowMessage ('Destroyed');
>  inherited;
> end;
>
> procedure abc(const a:Iunknown);
> var
>  b:IUnknown;
> begin
>  b := a;
>  b := nil;
> end;
>
> procedure TForm1.Button1Click(Sender: TObject);
> var
>  a: TMyInterfacedObject;
> begin
>  a:=TMyInterfacedObject.Create;
>  abc(a as IUnknown);
>  // Разрушается
> end;
>
> end.
>
>
> D7, все корректно разрушается.


Конечно все разрушается, но уже финализатором.


А я про момент тогда мы еще не дошли до финализатора.


oxffff   (2007-04-09 16:21:00) [29]


> ** не смог представить случай, когда такой изврат может
> понадобиться **


Ну это собственно пример.

Процедура abc может копировать, запрашивать интерфейсы вынуждая вызовы _addref, _Release, а может этого не делать.

Поэтому в первом случае
abc(А) нельзя гарантровано сказать жив объект А, или мерт.

Во втором случае
abc(А as Iunknown)
А жив всегда после возврата из abc.


Джо   (2007-04-09 16:20:00) [30]

> Здесь после вызова  abc объект a еще неразрушен.


type
 TMyInterfacedObject = class (TInterfacedObject, IUnknown)
 public
   destructor Destroy; override;  
 end;

implementation

{ TMyInterfacedObject }

destructor TMyInterfacedObject.Destroy;
begin
 ShowMessage ('Destroyed');
 inherited;
end;

procedure abc(const a:Iunknown);
var
 b:IUnknown;
begin
 b := a;
 b := nil;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
 a: TMyInterfacedObject;
begin
 a:=TMyInterfacedObject.Create;
 abc(a as IUnknown);
 // Разрушается
end;

end.


D7, все корректно разрушается.


clickmaker   (2007-04-09 16:15:00) [31]


> procedure abc(const a:Iunknown);
> var b:Iunknown;
> begin
> b:=a;
> b:=nil;
> end;

** не смог представить случай, когда такой изврат может понадобиться **


oxffff   (2007-04-09 16:06:00) [32]


> Объекты вроде всегда по ссылке передавались. Они не являються
> простым типом данных.


Здесь при передачи переменная а приводится Iunknown.


tesseract   (2007-04-09 16:03:00) [33]


> Компилятор нужно поправить, чтобы при передачи const интерфейса
> нужно создавать временную переменную,


Объекты вроде всегда по ссылке передавались. Они не являються простым типом данных.


Страницы:   1 2

Наверх

Титульная страница Поиск, карта сайта Написать письмо