Форум: "Потрепаться";
Текущий архив: 2005.02.27;
Скачать: [xml.tar.bz2];
ВнизПосягательство на святое… То бишь (шепотом) - компилятор Найти похожие ветки
← →
Ihor Osov'yak © (2005-02-09 16:46) [0]Или (может) ошибка в коде, генерируемом компилятором.
В общем-то такой безобидный код:
function iDocToString(const iDoc: IHTMLDocument2): string;
var
S: TStringStream;
begin
result := "";
if not assigned(iDoc) then
exit;
S := TStringStream.Create("");
try
(iDoc as IPersistStreamInit).Save(TStreamAdapter.Create(S), True);
Result := S.DataString;
finally
S.Free;
end;
end;
При танцах вокруг него было обнаружено, что деструктор TStreamAdapter не вызывается. На всякий случай - декларация IPersistStreamInit.Save:
function Save(const stm: IStream; fClearDirty: BOOL): HResult; stdcall;
то есть результат работы конструктора должен преобразовываться к интерфейсной ссылке, под которую компилятор неявно создает локальную переменную, и во время выхода которой из области видимости буде вызван _Release, которым в данном случае есть function TInterfacedObject._Release, так как TStreamAdapter наследуется от TInterfacedObject, ну и собственно из _Release должен быть вызван деструктор, так как счетчик ссылок будет сброшен в 0 (установка в 1 должна происходить в момент получения от созданного экземпляра TStreamAdapter интерфейса IStream перед передачей последнего как параметр для IPersistStreamInit.Save....
Но увы. деструктор не вызывался.
Мало того, при трассировании кода по CtrlAltC было установлено, что не вызывался не только _Release, а и _AddRef - то есть похоже компилятор забывает это делать для локальной интерфейсной ссылки, которую он сам и создает... Во всяком случае в этом примере кода. Провералось только в D7.
Да, если явно описать локальную интерфейсную ссылку:function iDocToString(const iDoc: IHTMLDocument2): string;
var
S: TStringStream;
iStm: IStream;
begin
result := "";
if not assigned(iDoc) then
exit;
S := TStringStream.Create("");
try
iStm := TStreamAdapter.Create(S);
(iDoc as IPersistStreamInit).Save(iStm, True);
Result := S.DataString;
finally
S.Free;
end;
end;
- то деструктор вызывается - но вопросы все же остаются - _AddRef вызывается только в момент присваивания iStm, а _Release - в момент ухода из области видимости. Но вот в момент вызова IPersistStreamInit.Save методы подсчета ссылок не дергается - и хотя во второй реализации функции это не критично, но все же.. бардак однако..
Собственно было бы интересно послушать мнение уважаемого сообщества относительно обрисованной выше фишки...
Имеет факт некоректности место быть, или присутсвует некоторое непонимание с моей стороны?
← →
Ihor Osov'yak © (2005-02-09 16:50) [1]Ой, похоже я не разобрался между междуфорумными перебросками..
← →
Гаврила © (2005-02-09 17:12) [2]
> бардак однако..
не бардак, а фича
← →
Ihor Osov'yak © (2005-02-09 17:27) [3]а почему фича? Бардак он и Африке бардак.
← →
Гаврила © (2005-02-09 17:37) [4]В африке бабуины программируют
http://www.newsru.com/world/06Aug2003/baboo.html
обленились ,панимаешь... все за них считают ,и адрефы ,и релизы ,а они еще и недовольны :-)))
а если серьезно
откуда компилятору знать, что ты туда подставил?
Нет у тебя интерфейсной ссылки на IStream в первом случае, просто нет
← →
Набережных С. © (2005-02-09 17:44) [5]>Ihor Osov"yak © (09.02.05 16:50) [1]
ИМХО, тут дело в спецификаторе const. Возникает некоторая неоднозначность, которую компилятор не может разрулить. Честно говоря, подробностей уже не помню, потому как разбирался с этим года три назад, а потом просто взял за правило. Я столкнулся с этим, когда после вызова некоторых методов импортированных интерфейсов объект "вдруг" уничтожался, хотя ссылки на него еще были. Дело оказалось в том, что некоторые интерфейсные параметры в ActiveX были объявлены без const. Когда исправил объявления, все заработало. Там, кстати, и некоторые параметры типа TGUID объявлены без const. Руки бы пообрывал:). И, по-моему, в каких-то других модулях я на такое-же нарывался. С тех пор взял за правило проверять объявление интерфейсов и редкоизпользуемых функций WinAPI, прежде чем к ним обращаться.
Если моя мысль верна, то проблема должна ичезнуть, если вызывать метод так:
(iDoc as IPersistStreamInit).Save(TStreamAdapter.Create(S) as IStream, True);
← →
Ihor Osov'yak © (2005-02-09 18:21) [6]2 Гаврила © (09.02.05 17:37) [4]
> Нет у тебя интерфейсной ссылки на IStream в первом случае, просто нет
Вот с этого места и поподробнее.
2 Набережных С. © (09.02.05 17:44) [5]
Спасибо, сейчас проверю. Оно выглядит более красиво и естественно, чем явное введение локальной переменной.
зы. Из за сбоев на сервере (или своей несообразительности) я создал дублирующую ветку - см. http://delphimaster.net/view/1-1107954615/
предлагаю дискуссию продолжать здесь - а стоящий внимания постинг с той ветки я цитирую сюда:
============
У (09.02.05 17:38) [2]
Это известная фича, обсуждалась, кажется, в Королевстве.
Т.е. результат работы конструктора к интерфейсному типу преобразуется,
а вот неявную локальную переменную компилятор не создаёт.
Да, наверное, и не должен.
--------------------------------------------------------------------------------
Ihor Osov"yak © (09.02.05 18:17) [3]
> Т.е. результат работы конструктора к интерфейсному типу преобразуется,
Это и понятно.
> а вот неявную локальную переменную компилятор не создаёт.
это его проблемы, но см. ниже.
Но он обязан вызвать _AddRef - так как начинает работать с обьектом по интерфейсной ссылке (передает как параметр в процедуру, то есть перед передачей параметра). С последующем вызовом _release, когда потеряет интерес к обьекту (после возврата из процедуры). Но вот вызвать _release без создания локальной переменной или чего то в этом роде он не сможет.
Посему с
> Да, наверное, и не должен.
несогласен.
То есть я все же пока настроен считать, что соотв. фича есть недоработка Борланда..
===========
Страницы: 1 вся ветка
Форум: "Потрепаться";
Текущий архив: 2005.02.27;
Скачать: [xml.tar.bz2];
Память: 0.5 MB
Время: 0.041 c