Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Потрепаться";
Текущий архив: 2004.08.01;
Скачать: [xml.tar.bz2];

Вниз

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

 
Piter ©   (2004-07-13 17:05) [0]

Вылавливал баг в своей программе и обнаружил интереснейшую вещь. Окаывается, оператор IS вызывает Acees Violation при определенных условиях!

В моей программе случай был сложный, конечно, но элементарной интерпретацией его может быть код:

<CDOE>procedure TForm1.Button1Click(Sender: TObject);
var
 frm : TForm;
begin
 frm := TForm1.Create(nil);
 frm.Free ;
 if frm is TForm1 then ;
end;

причем, лично у меня в Delphi 7.0 build 4.453 AV вылезает только после того, как два раза нажмешь на кнопку (?!).

Причем, как видно, последовательность именно такая, нужно объявить переменную типа какой-нибудь формы. А создавать и проверять нужно форму наследника от этой формы.
Вот при таких условиях вылезает AV. Почему - я не выяснил. Ошибка происходит где-то в недрах VCL, я копался, копался пол дня, так ничего и не выяснил.
Причем, с не формами такого не происходит.


 
stone ©   (2004-07-13 17:12) [1]

frm : TForm;
frm := TForm1.Create(nil);


 
Romkin ©   (2004-07-13 17:26) [2]

Хм... Сначала, значит, объект уничтожаем, а потом у него спрашиваем, что он такое? Оригинально.
А то, что не с формами - не возникает, так это просто повезло, что освобожденная память пока ничем другим не занята


 
Mystic ©   (2004-07-13 17:26) [3]

После строки frm.Free frm есть bad pointer (указатель неизвестно на что. Естественно, что если его попытаться как-то проинтерпретировать (is, as, ...), естьвариант, что результатом будет AV.

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


 
Тимохов ©   (2004-07-13 17:27) [4]


> Вот при таких условиях вылезает AV. Почему - я не выяснил.

т.к. frm <> nil


> Причем, с не формами такого не происходит.

все просто - везет.


 
Piter ©   (2004-07-13 17:29) [5]

Romkin ©   (13.07.04 17:26) [2]

ты не прав. К объекту я не обращаюсь! Оператор is приводит к вызову функции _IsClass, а та к вызову TObject.InheritsFrom
Но:

class function TObject.InheritsFrom(AClass: TClass): Boolean;

По твоей логике код:

procedure TForm1.Button1Click(Sender: TObject);
var
frm : TForm;
begin
if frm is TForm1 then ;
end;


должен сразу приводить к ошибке! Ан нет, он абсолютно безопасен...


 
Тимохов ©   (2004-07-13 17:33) [6]


> должен сразу приводить к ошибке! Ан нет, он абсолютно безопасен...

вполне может быть, т.к.
1. он вероятно будет исключен оптимизатором за ненадобностью.
2. опять же как повевезет.

:)))


 
Тимохов ©   (2004-07-13 17:34) [7]


> Piter ©   (13.07.04 17:29) [5]

и вообще - av это такая ошибка, хитрая. Не всегда явно ошибочный код приводит к исключению.


 
Тимохов ©   (2004-07-13 17:37) [8]


> Не всегда явно ошибочный код приводит к исключению.

а вот это может быть связано с тем, что bad pointer в дельфи не всегда таковой с точки зрения windows. Т.е. с точки зрения дельфи вы можете смотреть на уже убитый объект, а с точки зрения windows - на заразервированную и выделенную область виртуальной памяти. Т.е. никаких аv windows не даст.


 
Romkin ©   (2004-07-13 17:38) [9]

Piter ©  (13.07.04 17:29) [5] Мдя... Как раз только что на Брайнбенче встретил вопрос об этом. А почитать LangGuide никак? Если метод объявлен как метод класса, это всего лишь означает, что его можно вызывать как метод объекта, так и как метод экземпляра класса. Здесь он вызывается именно как метод объекта. Просто по здравому смыслу, чтобы узнать, объект какого класса лежит в переменной, надо обратиться конкретно к этому созданному объекту, посмотреть, на какой класс он ссылается


 
Anatoly Podgoretsky ©   (2004-07-13 17:47) [10]

В некоторых руках и Блокнот страшное оружие, в твоих руках IS страшное оружие


 
Digitman ©   (2004-07-13 17:56) [11]


> Оператор IS небезопасен для форм


редкого засола чушь ... достойна скрижалей истории


 
Тимохов ©   (2004-07-13 18:10) [12]

я думаю, автор уже покаялся :))


 
Piter ©   (2004-07-13 19:23) [13]

я прочитал все ваши сообщения и согласен с вами! Особенно благодарен за отзывы вроде "Ты ламер" и типа того, которые не несут никакой информативной выгоды.
Действительно благодарен Тимохову, который хоть с пониманием отнесся.

Я это все знаю, что вы пишите, просто поведение оператора IS ввело меня в заблуждение. Оказывается, все не так просто как я думал.

Более того, считаю, что Борланд поступает неправильно, реализовывая поведение оператора IS таким образом.

Ну и стоит добавить, что поведение данного оператора до сих пор мной до конца не понято :( Что поделать - я всего лишь мелкий ламерок.

Кстати, хочу сделать отступление насчет того почему я завел тему. Просто до этого я абсолютно не смотрел как реализован IS, хотя знал что он делает. Я его считал абсолютно безопасным, то есть над чем его не применяй - все отработает корректно, и ты получишь либо true, либо false. Я ошибался - я знаю.
Я думал, если btn это TButton, то IS вернет true при проверке. Если же нет или btn "умерший" экземпляр - то он вернет false (действительно, разве можно считать, что btn это TButton, если ему сделали Free?).
В общем, мои интуитивные представления о реализации IS разошлись с действительной реализацией Borland.

Все примеры рассматриваются с ВЫКЛЮЧЕННОЙ оптимизацией.

1) если результат IS можно "угадать" на этапе компиляции - то компилятор так и делает. Никакого вызова IsClass не будет!

Например:

procedure TForm1.Button1Click(Sender: TObject);
var
frm : TForm;
i: integer;
Flag: boolean;
begin
for i:=0 to 100000 do
 begin
   frm  := Pointer($FF45ACB3);
   Flag := frm is TForm ;
 end;
end;


frm указывает черт знает куда - но никакой ошибки не будет. Потому что никакого вызова IsClass тоже не будет.

Это позволяет сделать на мой взгляд хорошую штуку:

procedure TForm1.Button1Click(Sender: TObject);
var
btn : TButton;
begin
 btn := Pointer(TEdit.Create(nil));
 if btn is TButton then
   TButton(btn).Parent := self;
end;


Все понятно, я думаю. Но покажите человеку кусок кода

if btn is TButton then
 TButton(btn).Parent := self;


лично я бы был уверен, что на форме появится кнопка. Ведь IS проверил! Ан нет, на форме появится edit.

Конечно, это можно отнести к хакерскому методу создание edit"ов :) Я с этим согласен. Но по моему мнению если уж IS берется проверять какой это ДЕЙСТВИТЕЛЬНО класс, несмотря на то как был объявлен указатель на класс - то уж и пусть ВСЕГДА вызывается функция IsClass

2) Рассмотрим такой код:

procedure TForm1.Button1Click(Sender: TObject);
var
frm : TForm;
i: integer;
Flag: boolean;
begin
for i:=0 to 10000 do
 begin
   frm := TForm1.Create(nil);
   frm.Free ;
   Flag := frm is TForm1 ;
 end;
end;


Он приводит к AV уже на второй итерации (кстати, почему на второй?). Вроде все ясно, объект уничтожен, какого хрена вызывать его методы. Согласен.
Но ПОЧЕМУ такой вот код НЕ приводит ни к каким ошибкам:

procedure TForm1.Button1Click(Sender: TObject);
var
frm : TForm;
i: integer;
Flag: boolean;
begin
for i:=0 to 100000 do
 begin
   frm := TForm.Create(nil);
   frm.Free ;
   Flag := frm is TForm1 ;
 end;
end;


Как видно, всего лишь была заменена строка TForm1.Create(nil) на TForm.Create(nil)

Хотя и тут у меня есть догадки, но я очень плохо знаю ассемблер, чтобы убедиться :)

Пожалуйста, если кто хочет написать что-то типа "в твоих руках и пылесос оружие" то не надо!
Заранее спасибо!


 
Тимохов ©   (2004-07-13 19:29) [14]


> Более того, считаю, что Борланд поступает неправильно, реализовывая
> поведение оператора IS таким образом.

Уважаемый, не надо нам очередного "Грустно - до чего ламерство окрепло " (с) Igorek. Не осуждайте борланд.


> Но ПОЧЕМУ такой вот код НЕ приводит ни к каким ошибкам:

потому как везука вам.

> Хотя и тут у меня есть догадки, но я очень плохо знаю ассемблер,
> чтобы убедиться :)

не надо догадок - выбросте из головы.

запомните отверждение - из лжи следует как ложь, так и истина. Поэтому ошибочное место может как работать, так и не работать. Гадать тут нечего - читай утв. выше.


 
Piter ©   (2004-07-13 20:06) [15]

Тимохов ©   (13.07.04 19:29) [14]
Уважаемый, не надо нам очередного


а... вот так значит :)
Между прочит, я написал СЧИТАЮ. А считать я могу как угодно, верно? И никто еще меня не разубедил.

Тимохов, по-моему, ты заводил как-то ветку о языках. Ты говорил, что проштудировал раздел MSDN о Language Support  или как-то так. Тогда ты поделился своим мнением и выразил недоумение о том, что типа нафига Microsoft сделал так? Тогда Игорь Шевченко грубо сказал, что ты аля ламер и просто не разбираешься в матчасти.
Может, не надо теперь самому в аналогичной ситуации делать так, как тебя самого обидело, ок?!

потому как везука вам

везука мне? Увольте!  Сто тысяч раз повезло? :)
Вот это везение так везение :)))
Хотите я добавлю нолик и мне повезет миллион раз? Правда, по времени это будет дольше, но тем не менее повезет, я пробовал :)

Может все таки кто-нибудь снизойдет и обхяснит чем ПРИНЦИПИАЛЬНО отличаются примеры в пункте 2? Да так, что первый пример вызывает AV на второй итерации, не говоря уже о дальнейшем, а второй пример не вызывает ничего даже при 100000 итерациях! Мне это кажется удивительным. Вам нет? Ну что же я могу поделать...


не надо догадок - выбросте из головы

если ты не хочешь вникать в мои примеры - не надо. Надеюсь, что найдется еще кто-нибудь, кто вникнет.

Вообще, ты себя ведешь несколько по свински. Так высокомерно, мол "не надо догадок". Как будто сам никогда не высказывал никаких догадок, что в приведенном уже мной случае, что в случае загрузки из exe функциий, как из DLL.
Так вот тебе ответ - НЕ НАДО НИКАКИХ ДОГАДОК. Нельзя грузить функции из EXE. Вот и все, просто запомни - НЕЛЬЗЯ. И не надо никаких догадок...
А то что у тебя там что-то получилось - так это просто повезло!


 
Тимохов ©   (2004-07-13 20:12) [16]


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

Знаешь, прикол в том, что я оказался прав во всех утверждениях. :))

Зря вы так.
Скажу лишь (понимаю, что обижу, но поверьте, это на пользу) - порастете поймете.

ЗЫ. Примеры я все просмотрел.
ЗЫЫ. Я домой. Очень прошу не отвечайте пока. Подумайте, поанализируйте.
ЗЫЫЫ. Не повторяйте игорька.
ЗЫЫЫЫ. Все это делается с лучшими пожеланиями, т.е. :)))))))


 
Тимохов ©   (2004-07-13 20:15) [17]

и зря вы про exe вспонили.
загрузка exe это важная веха в понимании процессов и вообще исполняемого кода.

грузится дожно. Есть определенная особенность реализации в дельфи, которую я и хотел выяснить.

ЗЫ. Еще раз не обижайтесь и не горячитесь. Вон - игорек когда про числа с плав. точкой прочел - тоже офигел.

:)


 
Nous Mellon ©   (2004-07-13 20:16) [18]

2Piter
О посте [16]
Когда тебе неожиданно начинают говорить Вы вместо Ты это подчеркивает негштивное отношение.
2Тимохов
Может быть если не можете объяснить подождать когда придет специалист и расскажет, а не обвинять человека не зная ответа на его вопрос?


 
jack128 ©   (2004-07-13 20:27) [19]


> frm указывает черт знает куда - но никакой ошибки не будет.
> Потому что никакого вызова IsClass тоже не будет.
Именно так. Или ты бумаешь, что если переменная обявлена как TSameType, компилятор должен угадать - "нет, на самом деле - это TOtherType, которому сделалм приведение типа" , так чтоли ?

Вообще: ВСЕ ПРИВЕДЕНИЯ ТИПОВ ТЫ ДЕЛАЕШЬ НА ВСЕЙ СТРАХ И РИСК!!!!!!!!

По пункту 2) у меня AV в любом случае. Приколы менеджера памяти..


 
Piter ©   (2004-07-13 21:30) [20]

Тимохов ©   (13.07.04 20:12) [16]
Знаешь, прикол в том, что я оказался прав во всех утверждениях


да? А не случится такого прикола, что я здесь тоже буду прав во всех утверждениях? Ты не подумал?


Скажу лишь (понимаю, что обижу, но поверьте, это на пользу) - порастете поймете

ну чтож, последнее дело случилось. Обвинения в малолетстве. Чтож, Тимохов, понимаю что обижу, но я был о тебе лучшего мнения.
Ты сам не понял. Когда к тебе относились так, как ты сейчас относишься ко мне - тебя это раздражало. Это факт. У меня нет в архиве той ветки, а то я бы с удовольствием процитировал, как ты бесился, что на твое "Почему" тебе отвечали "учи матчасть" то есть грубо говоря посылали. И бесило вдвойне потому, что отвечал уважаемый мастер, которому ничего не докажешь.


и зря вы про exe вспонили.
загрузка exe это важная веха в понимании процессов и вообще исполняемого кода

Да ладно?
А я тебе говою - НЕЛЬЗЯ ГРУЗИТЬ EXE как DLL! Понимаешь? Не понимаешь - учи матчасть. Нельзя и все. То, что у тебя там что-то получилось - это повезло.

Nous Mellon ©   (13.07.04 20:16) [18]

спасибо.


Когда тебе неожиданно начинают говорить Вы вместо Ты это подчеркивает негштивное отношение

я тоже так считаю

jack128 ©   (13.07.04 20:27) [19]
Именно так. Или ты бумаешь, что если переменная обявлена как TSameType, компилятор должен угадать - "нет, на самом деле - это TOtherType, которому сделалм приведение типа" , так чтоли ?


нет! Я хотел сказать, что компилятору логичнее было бы вызывать IsClass в ЛЮБОМ СЛУЧАЕ. А не пытаться угадать, понимаешь?
Ведь IS должен проверять, является ли данный экземпляр таким-то классом, верно? А получается, что он не проверяет! Он не вызывает никакого кода, который бы определял что это за класс! Он тупо говорит - да, это нужный нам класс, хотя понятия не имеет о структуре, на которую этот экземпляр класса указывает.
Он просто исходит из предположения, что если была объявлена переменная класса такого-то, то значит она может указывать только на эземпляр данного класса или его потомков. Но ведь это не так, переменная может указывать куда угодно.


Вообще: ВСЕ ПРИВЕДЕНИЯ ТИПОВ ТЫ ДЕЛАЕШЬ НА ВСЕЙ СТРАХ И РИСК!!!!!!!!

да это ежу понятно. Я просто говорю о расширении функциональности оператора IS.

Ведь по интуиции, когда я пишу строчку:

Same is TOtherType

то в случае true я могу быть уверн, что действительно Same это экземпляр TOtherType или его потомка.
А если false - то я точно знаю, что Same не является ни экземпляром TOtherType, ни его потомков.

Ведь такой функционал подразумевается от IS, верно?

Но получается, что это не так. Получается, что ты ждешь от оператора одного, а получаешь другое. Это, конечно, мое мнение. Но согласитесь - оно имеет право на существование.

Как в примере:

if btn is TButton then
  TButton(btn).Caption := "Blah";


Ну покажи кому-нибудь такой код. Он скажет - абсолютно безопасный код, так как в мозгах прокручивается, что если is показало, что btn это TButton, а у TButton имеется свойство caption - то все верно. И этот код отработает на ура.

Ан нет! Получается, что btn может указывать куда угодно, а IS все равно "признает" его TButton"ом.

Вообщем, я хотел сказать только то, что зря компилятор так умничает. Логичнее, имхо, было бы вызывать IsClass ВСЕГДА при использовании IS. Это было бы гарантией того, что под btn скрывается действительно TButton, а не что-то мифическое.

Это, наверное, как вопрос религии. Лично я считаю, что описанное мной поведение IS было бы логичнее, чем существующее. Я просто не ожидал, что IS действует именно таким образом.

Да и вообще уверен, что многие не подозревают, что в случае:

var
 st: TSameType;
...
if st is TSameType then...


не генерируется никакого кода проверки и оператор IF всегда будет выполнен, несмотря на то, вызывался ли вообще конструктор для st или нет


 
Piter ©   (2004-07-13 21:31) [21]

jack128 ©   (13.07.04 20:27) [19]
По пункту 2) у меня AV в любом случае. Приколы менеджера памяти..


понятно... а у тебя какая Дельфи? Шестая?
У меня седьмая... интересно было бы, если еще кто протестировал эти две функции!


 
Nous Mellon ©   (2004-07-13 21:55) [22]

Тестил
Делфи 6
AV во втором случае нет

ИМХО Надо смотреть асмкод чтобы понять


 
jack128 ©   (2004-07-13 21:56) [23]


> нет! Я хотел сказать, что компилятору логичнее было бы вызывать
> IsClass в ЛЮБОМ СЛУЧАЕ. А не пытаться угадать, понимаешь?
Ты считаешь логичным, зная на 200% что 2*2=4, проверить это еще раз? Возможно было бы ПРОЩЕ, не анализируя тип переменной, сразу генерировать код по вызову IsClass, но уж точно не ЛОГИЧНЕЕ.


> понятно... а у тебя какая Дельфи? Шестая?
5


> Скажу лишь (понимаю, что обижу, но поверьте, это на пользу)
> - порастете поймете
>
> ну чтож, последнее дело случилось. Обвинения в малолетстве


> как ты бесился, что на твое "Почему" тебе отвечали "учи
> матчасть" то есть грубо говоря посылали. И бесило вдвойне
> потому, что отвечал уважаемый мастер, которому ничего не
> докажешь.

Теперь он подрос и уже не бесится ;-)   (*я понимаю, страсти кипят, но надеюсь поймете правильно ;-)*)


 
Григорьев Антон ©   (2004-07-13 22:10) [24]

А между прочим, Piter раскопал очень интересную вещь - такое неочевидное поведение компилятора. На Королевстве Delphi есть раздел "Подводные камни", где собирается информация о подобных случаях, когда ожидаешь одно, а получается совсем другое. Piter, напиши туда о том, что ты здесь накопал - примут с благодарностью. Раздел здесь: http://www.delphikingdom.com/stones/


 
Style ©   (2004-07-13 22:11) [25]


> У меня седьмая... интересно было бы, если еще кто протестировал
> эти две функции!


У меня 7 и тоже оба варианта не работают.

Зато вот так AV нет:

procedure TForm1.Button1Click(Sender: TObject);
var
frm : TForm1;
i: integer;
Flag: boolean;
begin
for i:=0 to 100000 do
begin
  frm := TForm1.Create(nil);
  frm.Free ;
  Flag := frm is TForm1 ;
end;
end;


> Piter ©   (13.07.04 21:30) [20]
> нет! Я хотел сказать, что компилятору логичнее было бы вызывать
> IsClass в ЛЮБОМ СЛУЧАЕ. А не пытаться угадать, понимаешь?
> Ведь IS должен проверять, является ли данный экземпляр таким-то
> классом, верно?

Я конечно могу ошибаться, но помоему
в том то и дело что экземпляр уже не существует. А адрес по которому проверяет _IsClass возможно по каким-то причинам доступен для чтения.
И даже то что InheritsFrom является классовым методом - это еще не о чем не говорит,
вызывается он все равно из экземпляра Child который уже не существует, т.е.
возможно в самом вызове Child.InheritsFrom нет реального обращения к адресу обекта, но вот указатель на объект помещается  в один из регистров и в дальнейшем используется в InheritsFrom.
И там тоже все стандартно, - если указатель
Bad Read Pointer (к примеру nil) то будет AV, но если по каким-то причинам данные по адресу доступны, то ошибки не будет.
Так что скорее всего тут все равно дело не в InheritsFrom. а в самом объекте Child который на данный момент является так называемым диким указателем , а то что эта область доступна для чтения - это нужно спросить у менеджера памяти.

А так главная ошибка в том что появился этот дикий указатель. Т.е. если бы после Frm.Free мы бы сделали Frm := nil; То мы 100% сняли бы этот вопрос.

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


 
Григорьев Антон ©   (2004-07-13 22:28) [26]

Уточню свой предыдущий пост: в Подводные камни я рекомендую вот это:

procedure TForm1.Button1Click(Sender: TObject);
var
btn : TButton;
begin
btn := Pointer(TEdit.Create(nil));
if btn is TButton then
  TButton(btn).Parent := self;
end;


 
Piter ©   (2004-07-13 22:49) [27]

Style ©   (13.07.04 22:11) [25]
Зато вот так AV нет:

procedure TForm1.Button1Click(Sender: TObject);
var
frm : TForm1;
i: integer;
Flag: boolean;
begin
for i:=0 to 100000 do
begin
 frm := TForm1.Create(nil);
 frm.Free ;
 Flag := frm is TForm1 ;
end;
end;


естесственно! Как я уже писал (интересно, кто-нибудь читает?) в данном случае никакой проверки не будет, IsClass НЕ ВЫЗЫВАЕТСЯ. О чем я и толдычу уже который пост. И это нелогично, имхо. Поэтому и никакого AV, Flag всегда будет True

Григорьев Антон ©   (13.07.04 22:10) [24]
Piter, напиши туда о том, что ты здесь накопал


ок

Мне интересно теперь почему у Nous Mellon ошибки нету в D6, у меня нету ошибки в D7, а у Style в D7 есть. И у Jack128 в D5 есть... непонятно как-то...

может, от версии ОС зависит еще?

P.S. Надо будет D5 поставить... где-то была на компакте...

jack128 ©   (13.07.04 21:56) [23]
Ты считаешь логичным, зная на 200% что 2*2=4, проверить это еще раз?


а тебе не кажется. что сравнение некорректно?!?!?! В том то и дело, что если бы компилятор был уверен, что btn это TButton - то да, нелогично. Но ведь вся фишка то в том, что из-за приведения типов btn оказывается может быть не TButton, а TEdit!!! В таком случае, имхо, не лишнее и  проверить!


 
Cobalt ©   (2004-07-13 22:53) [28]

Результаты тестирования в Delphi 4

1) if btn is TButton then
Просто-напросто сравнивает локальную переменную с 0.

2) Flag := frm is TForm1 ;
Генерируется IsClass.
Кстати, если после Free сделать frm:=nil;, то AV нет, Flag=False. Без обнуления - AV на первой же итерации (особенности менеджера памяти?).
3) frm := TForm.Create(nil);
Генерируется IsClass, Flag=False, AV нет.


 
Cobalt ©   (2004-07-13 22:54) [29]

Да, ОС - WinXP Eng Prof.


 
Style ©   (2004-07-13 23:02) [30]


> естесственно! Как я уже писал (интересно, кто-нибудь читает?)
> в данном случае никакой проверки не будет, IsClass НЕ ВЫЗЫВАЕТСЯ.
> О чем я и толдычу уже который пост. И это нелогично, имхо.
> Поэтому и никакого AV, Flag всегда будет True


Может я конечно чего и упустил, но если я ставлю BreakPoint в модуле System на единственой строке
function _IsClass(Child: TObject; Parent: TClass): Boolean;
то Я ВИЖУ ЧТО _IsClass  ВЫЗЫВАЕТСЯ. !!!!

_IsClass может не вызываться в том случае если компилятор посчитает что Flag: boolean далее не используется  в программе и код будет исключен оптимизатором.


 
DiamondShark ©   (2004-07-13 23:54) [31]


> Между прочит, я написал СЧИТАЮ. А считать я могу как угодно,
> верно?

Нет, не верно.
Это в вопросе бытия божия ты можешь считать как угодно.
А в техническом вопросе считать надо так, как написано в спецификации. Или вообще никак.


 
Piter ©   (2004-07-14 00:06) [32]

Style ©   (13.07.04 23:02) [30]
но если я ставлю BreakPoint в модуле System на единственой строке
function _IsClass(Child: TObject; Parent: TClass): Boolean;
то Я ВИЖУ ЧТО _IsClass  ВЫЗЫВАЕТСЯ. !!!!


Ты уверен, что IsClass вызывается именно при употреблении оператора IS? Вообще-то function _IsClass и так постоянно вызывается при работе программы.

Чтобы убедиться, создаешь новое приложение. Лезешь в опции проекта - снимаешь галочку оптимизации, ставишь галочку Use Debug DCU.

Кидаешь батон на форму, в обработчике пишешь:

procedure TForm1.Button1Click(Sender: TObject);
var
 frm : TForm;
 i: integer;
 Flag: boolean;
begin
for i:=0 to 100000 do
begin
 frm := TForm1.Create(nil);
 frm.Free ;
 Flag := frm is TForm1 ; // ЗДЕСЬ СТОИТ БРЕКПОИНТ
end;


Там где показано ставишь брекпоинт. Запускаешь приложение, нажимаешь на кнопку, срабатывает брекпоинт. Нажимаешь F7.
Неужели происходит вызов IsClass?!?!?!

Можно на брекпоинте нажать CTRL+SHIFT+C - посмотреть по асм коду вызывается ли IsClass - не должна!


 
Piter ©   (2004-07-14 00:07) [33]

DiamondShark ©   (13.07.04 23:54) [31]

Спасибо за пояснение! Большое спасибо!

P.S. Кто-нибудь из мастеров может рассказать - что же происходит на самом деле, а то они странным образом пропали куда-то...


 
DiamondShark ©   (2004-07-14 00:08) [34]


> Григорьев Антон ©   (13.07.04 22:10) [24]
> А между прочим, Piter раскопал очень интересную вещь - такое
> неочевидное поведение компилятора.

И что же там неочевидного?

The expression

object is class

returns True if object is an instance of the class denoted by class or one of its descendants, and False otherwise. (If object is nil, the result is False.)

Если к объекту применили Free, то он уже не является an instance of the class

Что неочевидного? Мануалы читать надо -- будет очевидно.


 
DiamondShark ©   (2004-07-14 00:10) [35]


> Piter ©   (14.07.04 00:07) [33]
> DiamondShark ©   (13.07.04 23:54) [31]
>
> Спасибо за пояснение! Большое спасибо!

Большое наздоровье.


> P.S. Кто-нибудь из мастеров может рассказать - что же происходит
> на самом деле, а то они странным образом пропали куда-то...

А в индексе справки набрать слово is религия не позволяет?


 
DiamondShark ©   (2004-07-14 00:15) [36]


> Piter ©   (14.07.04 00:06) [32]

А можно пояснить, в чём состоит глубокий общечеловеческий смысл в вызове is после Free?

Цитата из мануала: "...performs dynamic type checking" (выделение моё).

А теперь думаем, что значит dynamic? Вот мне кажется, что это что-то, основанное на особенностях конкретного экземпляра.
Впрочем, кто-то может СЧИТАТЬ иначе.


 
DiamondShark ©   (2004-07-14 00:17) [37]


> Григорьев Антон ©   (13.07.04 22:28) [26]
> Уточню свой предыдущий пост: в Подводные камни я рекомендую
> вот это:
>
> procedure TForm1.Button1Click(Sender: TObject);
> var
> btn : TButton;
> begin
> btn := Pointer(TEdit.Create(nil));
> if btn is TButton then
>   TButton(btn).Parent := self;
> end;


А отчего же не вот это:

btn := Pointer(12345);
if btn is ...


 
Cobalt ©   (2004-07-14 00:21) [38]

object is class
If the declared type of object is unrelated to class—that is, if the types are distinct and one is not an ancestor of the other—a compilation error results.

Sorry for my bad english, как это будет по русски?


 
DiamondShark ©   (2004-07-14 00:27) [39]


> Cobalt ©   (14.07.04 00:21) [38]

Если объявленый тип объекта object не имеет отношения к class -- типы разные и один не является наследником другого -- происходит ошибка компиляции.


 
Piter ©   (2004-07-14 00:36) [40]

DiamondShark ©   (14.07.04 0:08) [34]
Если к объекту применили Free, то он уже не является an instance of the class


А это значит, что IS вернет ... ?



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

Форум: "Потрепаться";
Текущий архив: 2004.08.01;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.61 MB
Время: 0.036 c
1-1090304726
npr2
2004-07-20 10:25
2004.08.01
определение ANSI-кода символа


4-1087385868
Regis
2004-06-16 15:37
2004.08.01
LPT в Win2k


1-1089896858
faost
2004-07-15 17:07
2004.08.01
StringGrid+ComboBox?


4-1087810017
Subdigger
2004-06-21 13:26
2004.08.01
CreateProcess


1-1089803621
Sparrow
2004-07-14 15:13
2004.08.01
как получить инфу о версии офиса на уровне прекомпилятора?





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский