Текущий архив: 2004.08.01;
Скачать: CL | DM;
ВнизОператор 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 вернет ... ?
← →
DiamondShark © (2004-07-14 00:44) [41]
> DiamondShark © (14.07.04 00:27) [39]
Пардон, не наследником, а предком.
Левый операнд должен иметь объявленый тип, являющийся предком правого. Или совпадать.
> Piter © (14.07.04 00:36) [40]
Не применима операция в этом случае вообще.
Слева должна быть коррекная ссылка на экземпляр, или nil.
← →
Piter © (2004-07-14 01:37) [42]DiamondShark © (14.07.04 0:44) [41]
Не применима операция в этом случае вообще.
Слева должна быть коррекная ссылка на экземпляр, или nil.
Ха-ха! Это ты когда придумал, сейчас или вчера? :)
Ты сам приводил цитату их help"а
>returns True if object is an instance of the class
И сам же говорил:
>Если к объекту применили Free, то он уже не является an >instance of the class
Теперь совмещаем эти два утверждения!
Получается, что оператор IS возвращает True, если объект является экземпляром нужного нам класса.
Но ты говоришь, что после Free объект уже не является экземпляром класса, верно? То есть, IS должен возвращать false, ведь так?
Заметь, я ничего не придумывал, я всего лишь цитировал ТЕБЯ, любимого :)
Так вот, несмотря на все это, несмотря на Free - хочешь я тебе построю пример, что Is все равно будет возвращать True?
← →
Sergey Kaminski (2004-07-14 06:32) [43]Прикольно тут всё, прикольно... или это все всерьез, Piter?
По-твоему, поведение оператораis
нелогично?
И всегда должен вызываться InheritsFrom? Вот так, например:
var
Btn: TButton;
begin
Btn := Pointer(123);
if Btn.InheritsFrom(TButton) then // заменим "нелогичный" is
ShowMessage("This is a TButton");
end;
Не смущает, что в таком случае AV будет всегда? Независимо "от версии Делфи". И количества итераций.
← →
KSergey © (2004-07-14 08:48) [44]Люди, хочу внести свои предложения.
1.Предлагаю не обсуждать вызовы каких-либо методов, операторов и проч. после Free. Очевидно, что это идиотизм чистейшй воды работать с дикими указателями. Получить можно все, что угодно. И не подадаваться на провокации по этому вопросу. Пиписьками уже давно все померялись.
2.Но мне так и не попалось здесь, признаюсь, причин, объясняющих отсутствие реальной проверки в коде, приведенном в [26] Григорьев Антон © (13.07.04 22:28). Происки оптимизатора? Или что? Или я так и не смог найти нужное место в хелпе, в котором бы говорилось, что реально проверка выполняется не всегда?
← →
Style © (2004-07-14 09:14) [45]
> Там где показано ставишь брекпоинт. Запускаешь приложение,
> нажимаешь на кнопку, срабатывает брекпоинт. Нажимаешь F7.
> Неужели происходит вызов IsClass?!?!?!
Только что проверил в D5 тоже происходит вызов _IsClass
Если интересно, то напиши после Is еще одну строчку например
if Flag then Caption := IntToStr(integer(Flag));
и поставь там тоже BreakPoint. Вызов IsClass произойдет раньше чем if Flag...
В D7 к тому же если ты остановишься ВНУТРИ функции IsClass то можешь проверить значения входных параметров Child и Parent если использовать Evaluate\Modify (Ctrl+F7) и в нем написать к примеру pointer(Child) то можно увидеть адресс экземпляра, указатель на который будет использован в InheritsFrom.
Можно эти адреса посмотреть и в программе:
Caption := Format("frm: %s, TForm1: %s",
[IntToHex(integer(frm),4),
IntToHex(integer(TForm1),4)]);
Кстати интересно что в D5 IsClass не содержит вызова InheritsFrom. Т.е. IsClass содержит почти тот же код что и InheritsFrom, только указатели на класс и экземпляр предварительно устанавливаются в регистрах самим компилятором.
← →
Cobalt © (2004-07-14 09:28) [46]2 Piter © (14.07.04 01:37) [42]
Миша, Миша, успокойся, пожалуйста!
Вот тебе цитаты из хелпа.
Class operators
The operators as and is take classes and instance objects as operands; as operates on interfaces as well.
----------
The is operator
The is operator, which performs dynamic type checking, is used to verify the actual runtime class of an object.
Достаточно?
← →
Григорьев Антон © (2004-07-14 09:59) [47]
> DiamondShark © (14.07.04 00:17) [37]
Продолжаю настаивать на том, что если укзатель указывает на TEdit, ожидаемое поведение is TButton для этого указателя - вернуть False, независимо от объявленного типа указателя.
Ну а что касается указателей после Free или указателей, указывающих неизвестно куда, то к ним никакие операции неприменимы и дают непредсказуемый результат - это аксиома. И устраивать проверки в разных версиях Delphi, ИМХО, бессмысленно - результат зависит от стечения множества факторов, которые делают результат непредсказуемым.
← →
Style © (2004-07-14 10:14) [48]
> Продолжаю настаивать на том, что если укзатель указывает
> на TEdit, ожидаемое поведение is TButton для этого указателя
> - вернуть False, независимо от объявленного типа указателя.
Ну дык тип самой переменной - является TButton, что даже по коду видно что тут, что-то не так.
Обычно если и делают приведение типов то и переменную объявляют того класса к которому относиться экземпляр. Или любой класс выше по иерархии.
Это вообще в своем уме нужно быть что бы написать
Button := Edit???
Объявите Btn по другому и все встанет на свои места.
var
btn : TControl;
← →
KSergey © (2004-07-14 10:25) [49]> [48] Style © (14.07.04 10:14)
Где написано, что не будет происходить явной проверки??? Что все соптимизируется??
← →
Тимохов © (2004-07-14 10:28) [50]
> Nous Mellon © (13.07.04 20:16) [18]
> не обвинять человека не зная ответа
укажите мне пальцем, где я его хоть в чем-то обвинил? :)
← →
Тимохов © (2004-07-14 10:30) [51]
> Piter © (13.07.04 21:30) [20]
Ну сейчас то я не бешусь :))
С благодарностью отношусь к:
1. ЮЗ
2. ИШ
3. АП
Пожалуй все - остальные редко отвечают на дурацкие вопросы.
И вы не перестанете бесится. Возможно, если не будете столько болезненно реагировать узнаете много нового - и меня добавите в этот спискок :)))
← →
Style © (2004-07-14 10:36) [52]
> Где написано, что не будет происходить явной проверки???
> Что все соптимизируется??
Еще раз, все приведения делаются на свой страх и риск!! (повторяю Jack128)
Если уже и произошло приведение типов,
Button := TButton(Edit);
то там одному богу только известно, что произойдет далее в программе.
Это равносильно тому, что и в игровой автомат, вместо 2-х рублей, пивную крышку запихивать. Автомат ругается, нельзя говорит! А мы эту крышку молотком туда забиваем.
Ситуации разные бывают. Можно и некоторое время с Button"ом как с Edit"ом работать пока дело не каснется того, что обращение произойдет к непосредственным свойствам TEdit.
← →
Cobalt © (2004-07-14 10:42) [53]2 Style © (14.07.04 10:14) [48]
Проверка - это проверка. И отсутствие её не может быть оправдана ничем. А то, что мы видим - это похоже на оптимизацию (которой здесь быть не должно).procedure TForm1.Button1Click(Sender: TObject);
var
btn : TControl;
begin
btn := Pointer(TEdit.Create(nil));
if btn is TButton then
TButton(btn).Parent := self;
end;
Вот тут есть проверка.
← →
Style © (2004-07-14 10:47) [54]Тут все правильно:
Зачем проверять Btn: TButton если он и так TButton.
А то что ты туда Edit подсунул - это твои проблеммы.
← →
Style © (2004-07-14 10:55) [55]В принципе вот так пройдет проверка.
var
btn : TButton;
begin
btn := Pointer(TEdit.Create(nil));
if TObject(btn) is TEdit then
TButton(btn).Parent := self;
← →
Тимохов © (2004-07-14 10:58) [56]Подумав надо сообщение Питера решил подвести свое резюме.
Питер сказал по сути две вещи:
1. Почему так неочевидно работает кодprocedure TForm1.Button2Click(Sender: TObject);
var
btn: tbutton;
begin
btn := Pointer(TEdit.Create(nil));
if btn is TButton then
TButton(btn).Parent := self;
end;
2. Почему неустойчиво работает кодvar
frm : TForm;
i: integer;
Flag: boolean;
begin
for i:=0 to 10000 do
begin
frm := TForm.Create(nil);
frm.Free ;
Flag := frm is TForm1 ;
end;
end;
Позвольте провести исследование.
1. В п1 надо решить два вопроса - почему работает неочевидно и почему вообще работает (я бы не тесрируя сказал, что будет av). Начем со второго - почему нет av. Все очень просто - у tedit и tbutton общий предок - tcontrol, который содержит parent. Даже несмотря на то, что setparent virtual - все работает - т.к. и у tbutton и у tedit этот метод и сам fparent на одном месте в vmt и памяти соответсвенно.
По поводу второго - неочевидного поведедения is. Вполне согласен, что поведение неочевидно. Согласен также в Григорьевым Антоном, что это достойная статься (или заметка) на королевство в обозначенный раздел. Объяснить почему так - тоже не сложно. Очевидно, что is является не просто функцией, а директивой, обладающей свойством compiler magic. Обладание compiler magic я и раньше замечал, но не до такой степени. Поэтому несколько лет назад и перестал ей пользоваться - только inheritsfrom - он не врет.
2. По п2. Нет смысла тестировать этот код. Очевидно, что работоспособность приведенного кода зависит от огромного количества факторов. Очевидно лишь одно - этот код ошибочен. Объясню почему. Посмотрите на п1 моего ответа. Я сказал про compiler magic операции is. И в первом примере Питера (где TFrom1) и во втором (где TForm) is трансформируется в вызов методов из frm (isclass). В одном случае ошибка усть, в другом нет - это везение. Другой вопрос, если бы код переписать такvar
frm : TForm1;
i: integer;
Flag: boolean;
begin
for i:=0 to 10000 do
begin
frm := TForm1.Create(nil);
frm.Free ;
Flag := frm is TForm1 ;
end;
end;
В этом случае на строчке Flag := frm is TForm1 сработает указанный мной compiler magic. И никаких вызовов не будет.
Итоговое резюме - понимаю почему Piter так реагирует - открыл новость, а никто не одобряет. Piter, спокойнее, все сказано выше. :)))
PS. Piter! Я уверен, что вы будете удовлетворены вниманием уделенным мной вашему вопросу. Я бы и вчера это смог написать - домой надо было. Если обидет прошу прощения.
ЗЫЫ. На протяжении всего поста вы меня превратно понимали.
ЗЫЫЫ. По поводу свойства compiler magic операции is. Сами понимаеете, что данное свойство не являтеся документированным. В дельфи таких штук полно. Например таже функция Dispose - тоже compiler magic. И тоже не все это знали. Я тоже долго возмущался - почему никто не хочет меня слушать.
Однако сделал из этого всего вывод - compiler magic можно постичь только изучая cpu. И если кто-то этого не знает - значит он и без этого знания живет хорошо. И горячится перестал.
← →
Тимохов © (2004-07-14 11:01) [57]
> Григорьев Антон © (14.07.04 09:59) [47]
> Продолжаю настаивать на том, что если укзатель указывает
> на TEdit, ожидаемое поведение is TButton для этого указателя
> - вернуть False, независимо от объявленного типа указателя.
с этим нельзя не согласится.
← →
Style © (2004-07-14 11:05) [58]Еще раз ИМХО!
Зачем проверять лишний раз то что
TObject(Object) is TObject = true;
Это изврат!!!
Is используют если для других целей
Object is TStrings
или
Object is TComponent
Вот в этом есть еще какой-то смысл.
А использовать Is для самого себя - безсмысленно...
А вот почему происходит оптимизация в этом моменте даже когда я Оптимизацию Отключил - вот это уже интересно. :)
← →
Тимохов © (2004-07-14 11:08) [59]
> А вот почему происходит оптимизация в этом моменте даже
> когда я Оптимизацию Отключил - вот это уже интересно. :)
это не оптимизация - это магия компилятора. Он часто такие вещи делает не обращая внимания на опцию опитмизации. Т.е. это свойство компилятора как такового.
← →
Тимохов © (2004-07-14 11:12) [60]
> да? А не случится такого прикола, что я здесь тоже буду
> прав во всех утверждениях? Ты не подумал?
во всех не окажешся.
в некторых да.
а я (лично) тебе вообще противоречил в утверждениях, в которых ты оказался прав? Ткни, что ли.
ЗЫ. Еще раз повторю - зря ты про exe. Exe должне грузится - если он не грузится, то это особенность компилятора дельфи, которую не в состоянии постичь ни сам, ни читая матчасть.
PS. Попрошу выделенную жирным фразу не убирать в случае возврата к теме exe. :)))
← →
Style © (2004-07-14 11:17) [61]
> Тимохов © (14.07.04 11:12) [60]
> Piter © (14.07.04 01:37) [42]
Ой ребята только не ругайтесь :)
← →
Тимохов © (2004-07-14 11:19) [62]
> Style © (14.07.04 11:17) [61]
да, кто ругается.
просто он воторой раз вырезал фразу из контекста.
я его поправил :))))
← →
DiamondShark © (2004-07-14 12:02) [63]
> Piter © (14.07.04 01:37) [42]
"Дядя Петя, ты дурак?" (ц) кинофильм.
Общее правило работы со ссылками: после освобождения ссылки единственная допустимая к ней операция -- присваивание нового значения.
Ты так и не объяснил, в чём тебе видится смысл в каких-то проверках после уничтожения экземпляра.
← →
Тимохов © (2004-07-14 12:05) [64]
> Ты так и не объяснил, в чём тебе видится смысл в каких-то
> проверках после уничтожения экземпляра.
ну думаю смысла автор и не видит и понял все свои ошибки (об этом он явно сказал), просто вынес на суд общественность открытый им факт магии компилятора в отношении директивы is.
PS. Вообще говоря интеренсный вопрос. Знает ли кто-нибудь статьи (можно на английском), посвященные магии компилятора дельфи? Очень интересно было бы прочесть.
← →
DiamondShark © (2004-07-14 12:08) [65]
> Григорьев Антон © (14.07.04 09:59) [47]
Да продолжайте настаивать хоть на том, что земля плоская!
С каких таких мухоморов указатель, объявленый как TButton может принять значение, не являющееся наследником TButton?
← →
Aldor_ (2004-07-14 12:43) [66]> С каких таких мухоморов указатель, объявленый как TButton может принять значение, не являющееся наследником TButton?
Я, конечно, по сравнению с Вами новичок, но какое отношение is и as имеют к объявлению? Ведь можно написать и TObject(AnyPointerVariable) is ..., а там уже смотрится, куда ссылается указатель (по-моему, в книге Марко Кэнту is и as даже приписывались к RTTI).
Поправьте меня, если я не прав.
← →
Cobalt © (2004-07-14 13:02) [67]После некоторых опытов с Дельфями, уяснил для себя следующую вещь:
1) Если переменная некоторого класса (var1
) проверяется на
var1 is It"sClassTypeOrOneOfParentClassType
,
то IsClass не вызывается - просто проверяется, assigned ли эта переменная.
2) Если проверяется на
var1 is It"sClassTypeDescendent
,
то тогда вызывается IsClass.
3) При попытке проверить на
var1 is SomeOtherClassType
при компиляции ругнётся.
4) При попытке привести кSomeOtherClassType
или присвоить ей явно объект типаSomeOtherClassType
также ругнётся при компиляции.
5) Если присваивать переменной фигню типаPointer(bla-bla-bla)
- это уже твоя головная боль - делай общего предка, и баста! (если хочешь нормально работать, а не воевать с классами)
Вроде ничего не упустил?
← →
Тимохов © (2004-07-14 13:05) [68]
> Вроде ничего не упустил?
вроде как.
← →
Piter © (2004-07-14 13:36) [69]Sergey Kaminski (14.07.04 6:32) [43]
Не смущает, что в таком случае AV будет всегда? Независимо "от версии Делфи". И количества итераций
НЕ смущает! Потому что ты указал ссылку НЕ на экземпляр класса, а на ЧЕРТ ЗНАЕТ ЧТО! Получил AV в программе! Задумался, оттрасировал программу, нашел ошибку, понял, исправил!
А вот тебя не смущает, что "ЛОГИЧНЫЙ" Is вернет TRUE в этом случае? Не кажется, что логика программы может пойти неправильным путем? Ибо указатель на хрен знает что признается указателем на TButton?
Style © (14.07.04 9:14) [45]
Если интересно, то напиши после Is еще одну строчку например
if Flag then Caption := IntToStr(integer(Flag));
и поставь там тоже BreakPoint. Вызов IsClass произойдет раньше чем if Flag...
Странно ты проверяешь. Мало ли что раньше, что позже. Ты должен установить брекпоинт на строчке с IS, а потом нажать F7 - если произойдет вход в функцию IsClass - значит, она вызывается.
Хорошо, ты можешь поставить брекпоинт на строчке с IS, нажать CTRL+SHIFT+C и привести код в асме?
DiamondShark © (14.07.04 12:08) [65]
С каких таких мухоморов указатель, объявленый как TButton может принять значение, не являющееся наследником TButton?
очевидно с каких. Из-за приведения типов. И даже не говори, что это не корректно. Буду обращаться с переменной, объявленной как TButton в контексте TEdit и никогда не получу AV. Потому как что TButton, что TEdit являются обычными Pointer, указателями на структуру, на область памяти. А что там хранится... это и есть задача Is :)
KSergey © (14.07.04 8:48) [44]
Предлагаю не обсуждать вызовы каких-либо методов, операторов и проч. после Free. Очевидно, что это идиотизм чистейшй воды работать с дикими указателями
согласен. Просто было жутко интересно почему не возникает AV у меня... ну просто мне интересно... ведь я проводил миллион итераций и никаких AV, ничего! Мне кажется это удивительным. Я не спорю, что неправильное обращение к любому участку памяти не всегда приводит к AV, может и "прокатить"... но миллион раз?! Мне кажется что миллион раз это слишком...
Cobalt © (14.07.04 9:28) [46]
Вот тебе цитаты из хелпа
The is operator
The is operator, which performs dynamic type checking, is used to verify the actual runtime class of an object
Да, да, я согласен! Но ведь в моем примере под пунктом 1 btn является вполне себе актуальным указателем! Правда, указывает на TEdit - но ведь иструкции хелпа не нарушены.
Style © (14.07.04 10:36) [52]
Это равносильно тому, что и в игровой автомат, вместо 2-х рублей, пивную крышку запихивать. Автомат ругается, нельзя говорит! А мы эту крышку молотком туда забиваем
ОТЛИЧНОЕ СРАВНЕНИЕ! Да, мы туда запихиваем крышку молотком и при этом автомат принимает эту крышку за монету! Понимаешь, в чем дело?
Я говорю про то, что автомат в любом случае, даже если в него впихнули пивную крышку НЕ должен принять ее за монету. Он может сломаться, но он не должен принять крышку за монету, понимаешь?
А ты говоришь, что нет, у автомата есть прорезь именно для монеты. И в эту прорезь не войдет пивная крышка при обычных условиях. Поэтому и нефига проверять, монета или не монета - если влезло, значит монета.
Но как ты понимаешь это может оказаться не монета :) Если поработать молотком.
Так вот тут тоже самое. Мы поработали молотком и Дельфи принял нашу пивную крышку за монету. Хотя теоретически мог быть устроен так, что должен был в любом случае проверять - а действительно ли это монета? Вот об этом мы и говорим.
Тимохов © (14.07.04 10:58) [56]
я полностью согласен с твоим постом. Абсолютно.
Итоговое резюме - понимаю почему Piter так реагирует - открыл новость, а никто не одобряет
ну типа того. И не то, что не одобряет. Ладно бы всем присутствующим это было абсолютн очевидно - промолчали. Ну ладно, подумаешь. Я действительно открыл для себя неочевидное поведение Is. Что же тут такого...
Но появляются люди, которые говорят "ты дурак". Читай хелп и снизойдет на тебя просветление. Это раздражает. Между прочим, я потратил немало времени разбирая эту проблему.
Плюс есть еще люди, которые говорят, что на самом деле именно такое поведение Is очевидно. Тут я просто не согласен. Ну не могу я назвать поведение очевидным, когда по сути экземпляр TEdit признается за TButton.
Однако сделал из этого всего вывод - compiler magic можно постичь только изучая cpu. И если кто-то этого не знает - значит он и без этого знания живет хорошо. И горячится перестал
а вот не надо делать плевков в мою сторону :) Я то как раз смотрел CPU и говорил об этом. И собственно поведение IS я объяснил еще на первой странице топика, собственно по этому поводу и неудомевал - почему не происходит вызова IsClass?
В общем ф-у-у-у )
Можно подвести итоги.
Название ветки неправильное. Тут я ошибался. IS может быть опасным как для форм, так и не для форм. Тут дело в непонятной мне работе менеджера памяти Дельфи.
По пунктам:
1) думаю, большинство признало, что IS должен вызывать IsClass в любом случае, пусть даже ценой AV в некоторых случаях (ошибка в программе хоть вскроется быстрее).
Ибо сейчас он может "признать" что угодно любым классом. Это неочевидно (по крайней мере, многие так считают).
2) Примеры неправильные - это я знаю. Ну просто интересно мне - почему даже при миллионе итераций ошибок нет. Ну не бывает такого везения. Хотелось бы копнуть поглубже, но там код на асме, а я его понимаю с трудом (считай, не понимаю).
← →
Aldor_ (2004-07-14 13:41) [70]Cobalt © (14.07.04 13:02) [67]
Оказалось, что я не прав, спасибо за разъяснения.
← →
Тимохов © (2004-07-14 13:44) [71]
> Мне кажется что миллион раз это слишком...
почему?
если в памяти ничего не менялось, то хоть через 10^10 итераций не будет av.
> Но появляются люди, которые говорят "ты дурак
такого тебе никто не говорил. :)))
> а вот не надо делать плевков в мою сторону
вы определенно на взводе :)))) много трактуете настолько превратно, что даже пояснять не хочу :)
> Ну не бывает такого везения
если прыгать с пятого этажа на батут при неизменность положения батута, пятого этажа, ветра, угла притяжения, сонечной активности, плотности воздуха - очевидно, что всегда будешь падать на батут :)
что тут не ясно? :)
← →
Тимохов © (2004-07-14 13:49) [72]Забыл прокомментировать это
> 1) думаю, большинство признало, что IS должен вызывать IsClass
> в любом случае, пусть даже ценой AV в некоторых случаях
> (ошибка в программе хоть вскроется быстрее).
Я не признал, и признавать не собираюсь.
Сломать можно, что угодно если отходить от правил. Да, может болланд виноват, что не совсем хорошо в данном вопросе отработал "защиту от дурака". Но все же не его вина в таком поведении.
Я могу привести массу примеров работы с интерфейсами, когда невинный код приводит не всегда даже к av, иногда к privileged instruction. Что с этого - interface сделаны не верно.
ЗЫ. Когда я упомянул про тему "Грустно - как окрепло ламертсво" думаю, вы меня не верно поняли. Вы помните о чем там было. Суть была такая, что автор после прочтения статьи о числах начал обвинять борланд. Я НЕ имел в виду сказать вам, что вы л. Я хотел сказать, что поспешные (чисто по времени осмысления, а не по глубине :))) суждения бывают силишком эмоциональные. Не в меру. :)))))
← →
STYLE © (2004-07-14 13:59) [73]
> Странно ты проверяешь. Мало ли что раньше, что позже. Ты
> должен установить брекпоинт на строчке с IS, а потом нажать
> F7 - если произойдет вход в функцию IsClass - значит, она
> вызывается.
В том примере вызов IsClass происходит
Piter © (14.07.04 00:06) [32]
Call IsClass...
> ОТЛИЧНОЕ СРАВНЕНИЕ! Да, мы туда запихиваем крышку молотком
> и при этом автомат принимает эту крышку за монету! Понимаешь,
> в чем дело?
Я говорил про то, что автомат сломался и принял эту пивную крышку, и что мы туда ее силой (молотком) запихали.
Так вот в вашей ситуации молотком является - приведение типов.
← →
Тимохов © (2004-07-14 14:01) [74]в сравнении с автоматом поддерживаю style.
если по автомату долбануть хорошо - то он и песни запоет и станцует лишь бы не били.
заяц "да слон, я слон, только сапогами по голове не бейте" (с) Анекдот.
← →
DiamondShark © (2004-07-14 14:09) [75]
> Aldor_ (14.07.04 12:43) [66]
> > С каких таких мухоморов указатель, объявленый как TButton
> может принять значение, не являющееся наследником TButton?
>
> Я, конечно, по сравнению с Вами новичок, но какое отношение
> is и as имеют к объявлению?
Прямое. Их область определения так введена.
> Ведь можно написать и TObject(AnyPointerVariable)
> is ..., а там уже смотрится, куда ссылается указатель
Можно. Можно и TObject(12345) написать. Только чьи это проблемы?
> (по-моему, в книге Марко Кэнту is и as даже приписывались к RTTI).
Верно, is и as и есть документированый механизм работы с RTTI.
А теперь внимание, вопрос. Каким образом определить, сослался ли указатель на структуру RTTI, просто на какой-то кусок памяти, или вообще за пределы адресного пространства?
Ответ: никаким.
← →
Cobalt © (2004-07-14 14:37) [76]2 Piter © (14.07.04 13:36) [69]
Ты согласен, что Cobalt © (14.07.04 13:02) [67] - вполне разумные ограничения?
← →
Sandman25 © (2004-07-14 14:46) [77]type
TOne = (Zero);
procedure TForm1.FormCreate(Sender: TObject);
var
One: TOne;
begin
One := TOne(5);
ShowMessage(IntToStr(Ord(One)));
end;
ИМХО, из той же серии. $R+, $Q+ не выявляют никаких ошибок.
← →
Piter © (2004-07-14 14:56) [78]Тимохов © (14.07.04 13:44) [71]
если прыгать с пятого этажа на батут при неизменность положения батута, пятого этажа, ветра, угла притяжения, сонечной активности, плотности воздуха - очевидно, что всегда будешь падать на батут :)
понимаю, что вы хотите сказать. Только почему в D5 "положение батута, пятого этажа, ветра, угла притяжения, сонечной активности, плотности воздуха" изменяется, а в D6 и D7 нет? Вот в чем вопрос. Да, вопрос может и не имеет практического применения. Но есть такое понятие как любопытство. Мне просто интересно почему.
>если в памяти ничего не менялось, то хоть через 10^10 >итераций не будет av
так вот почему в памяти D7 и D6 ничего не меняется, а в D5 меняется.
Тимохов © (14.07.04 13:44) [71]
> Но появляются люди, которые говорят "ты дурак
такого тебе никто не говорил. :)))
ну ладно, намекали :)
>"Дядя Петя, ты дурак?" (ц) кинофильм
Тимохов © (14.07.04 13:49) [72]
>думаю, большинство признало, что IS должен вызывать >IsClass
Я не признал, и признавать не собираюсь
ну что же :) Я понял :) Не думай, что я страдаю паранойей, просто очевидно, что когда о проблеме говорю я - ты ее не признаешь проблемой (считаешь, что уровень твой выше моего, поэтому я не могу выдвинуть проблем о которых ты не знаешь).
Потому что ты только что написал, что не признаешь такое поведение Is НЕОЧЕВИДНЫМ.
И в тоже время:
Тимохов © (14.07.04 11:01) [57]
> Григорьев Антон © (14.07.04 09:59) [47]
> Продолжаю настаивать на том, что если укзатель указывает
> на TEdit, ожидаемое поведение is TButton для этого указателя
> - вернуть False, независимо от объявленного типа указателя.
с этим нельзя не согласится.
И в тоже время ты согласен с Григорьевым Антоном, который считает, что поведение is неочевидно, ибо он должен вернуть false, а возвращает true.
Или говоря по другому. Когда я говорю, что поведение is неочевидно - ты со мной не согласен. Когда Антон говорит, что поведение is неочевидно - ты пишешь, что с
этим нельзя не согласиться!!!
А потом сам же пишешь что не согласен :)))
Я абсолютно не на взводе, я уяснил что к чему и сейчас мною движет просто любопытство. Я ничего не придумывал, я просто цитировал твои фразы. Ты явно говорил, что согласен с Антоном и также явно говорил, что не согласен со мной. Хотя мы с Антоном говоим одну и туже вещь - поведение IS не всегда неочевидно :)
Очень интересно что ты скажешь. Так сказать, хотелось бы услышать комментарий :)
← →
STYLE © (2004-07-14 15:00) [79]Мастера, где же вы???? Разъясните проблемму :)
← →
KSergey © (2004-07-14 15:10) [80]> Cobalt © (14.07.04 13:02)
По-моему, очень хороший пост.
И на мой взгляд, в хелпе это не написано. Хотя и не буду настаивать, не очень силен.
← →
Тимохов © (2004-07-14 15:16) [81]
> Очень интересно что ты скажешь. Так сказать, хотелось бы
> услышать комментарий :)
согласится Григорьевым Антоном я поспешил.
Я проложаю утверждать, что поведение is соответствует его цели.
для реализации поведения Антона есть inheritsfrom.
Хотя согласен, что они могли бы это реализовать и по-другому. Это не наше дело - такой компилятор. Но частной цели для которой разработан и документирован is все соответствует на 100 процентов.
>
> ну ладно, намекали :)
определенно параноик :))))
> так вот почему в памяти D7 и D6 ничего не меняется, а в
> D5 меняется.
потому, что так сложились обстоятельства.
прими как аксиому.
ЗЫ. Знаешь, чтобы копать в этой области вот тебе списко тем, после изучения которых ты можешь делать НЕумозрительные заключения:
1. Арихтектура виртуальной памяти windows.
2. обработка структурных исключений (в частности откуда и когда берется av)
3. менеджер памяти дельфи (статья Мистика есть на королевстве).
4. как создается объект (tobject.newinstance)
5. как и где хранятся такой повседневный тип как ansistring.
Вот после этого сможешь делать предположения и вообще НЕ принимать мою аксиому. Разработай свою (в точности равную моей) Но! До нее ты допрешь сам.
:)))))
← →
Sergey Kamininski (2004-07-14 15:19) [82]2 Piter © (14.07.04 13:36) [69]
НЕ смущает! Потому что ты указал ссылку НЕ на экземпляр класса, а на ЧЕРТ ЗНАЕТ ЧТО! Получил AV в программе! Задумался, оттрасировал программу, нашел ошибку, понял, исправил!
:) А ты указал ссылку не на экземпляр класса TButton, а на ЧЕРТ ЗНАЕТ ЧТО, приведенное к типу TButton. А потом пытаешься выяснить у компилятора, чтобы он таки четко тебе сказал, что это: баттон или мусор в памяти (а как он, интересно об этом догадается) или нечто, приведенное к типу баттона?
См. также: DiamondShark © (14.07.04 14:09) [75] <-- regards:)
← →
Тимохов © (2004-07-14 15:24) [83]Piter.
Повторюсь, что про compiler magic команды is я знал. Т.е. не ты мне это открыл.
Но!!! Тебя не удивляет, что тема странности is вообще (имхо) ни разу не возникала?
Меня не удивляет - у is есть определенное назначение, которое, согласен, не вполне удачно описано в документации. Но все же - ни у кого вопросов это не вызывает, т.к. все понимают о чем речь - пользуйся так как пользуется этим, например, сам борланд в vcl и проблем не будет.
Т.е. мое имхо такое - тебе сложно вынести, что ты неверно понимал is и поэтому ты ищешь причины. В частности причины найдены в доке - действительно описание дурацкое. Но это ничего не изменит - как пользовались все is для того, для чего он был разработан (но, повторюсь, плохо задокументирован) так и будут пользоваться :))))))
← →
Тимохов © (2004-07-14 15:26) [84]
> Sergey Kamininski (14.07.04 15:19) [82]
я тут прочел описание is (d6) и понял, что нельзя не согласится с piteroм в том, что описание не соответсвует семантике. Что я по этому поводу думаю я написал в предыдущих двух ответах.
Автору
Согласен с Антоном Григорьевым - пиши на статью.
ЗЫ.
Нужна ли, правда, она будет кому-то - не знаю :)) Но для общего образования полезна.
← →
Sergey Kamininski (2004-07-14 15:50) [85]2 Тимохов © (14.07.04 15:26) [84]
Ну, несоответствует, так сказать, частично ;)
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.
Но намекают ведь, чтобы не баловались и не подсовывали операнду ерунду всякую ;-)
← →
Тимохов © (2004-07-14 15:52) [86]
> Sergey Kamininski (14.07.04 15:50) [85]
не здесь не соответствует - в самом начале
The is operator, which performs dynamic type checking, is used to verify the actual runtime class of an object.
вот здесь.
← →
Sandman25 © (2004-07-14 15:54) [87]P: Pointer;
type
TR1 = record
a: integer;
end;
TR2 = record
a: byte
end;
var
R1: TR1;
P := @R1;
if P is TR1 then
...
if P is TR2 then
...
Конечно, даже не откомпилируется. Но, возможно, поможет автору понять, почему реализовать is так, как он этого хочет, не получится.
И, кстати, можно написать такой пример, чтобы даже InheritsFrom вернула неверный результат. Для этого нужно досконально изучить, как хранятся TObject, создать соответсвующие структуры, чтобы при том алгоритме, с помощью которого происходят вызовы методов, произошла передача управления по нужному адресу. А по этому адресу можно записать машинный код (типа DB из ассемблера). Только, наверное, надо будет еще установить нужные флаги у страниц памяти.
← →
DiamondShark © (2004-07-14 16:03) [88]
> Тимохов © (14.07.04 15:52) [86]
А в чём несоответсвие? Или неочевидность.
Вообще, в чём недостаток описания?
← →
Sergey Kamininski (2004-07-14 16:04) [89]Сторонникам автора ветки
Милые, родные, хорошие! А как же вы предлагаете реагировать компилятору на подобный кусок, а?
procedure TForm1.Button1Click(Sender: TObject);
var
btn : TButton;
begin
btn := Pointer(TEdit.Create(nil));
if btn is TButton then
TButton(btn).Parent := self;
end;
Ну что здесь можно предложить, кроме существующей реализации оператора? Что вы, в самом деле?..
Как можно всерьез об этом говорить?
← →
Тимохов © (2004-07-14 16:05) [90]
> DiamondShark © (14.07.04 16:03) [88]
в двух словах dynamic и runtime.
дело в том, что в рельаности runtime в некторых случаях = compiletime.
← →
Тимохов © (2004-07-14 16:06) [91]Я не сторонник автора во всем, я сторонник некторых моментов, которые он заметил.
> Ну что здесь можно предложитб
например вызов inheritsfrom(TButton)
← →
KSergey © (2004-07-14 16:08) [92]> [89] Sergey Kamininski (14.07.04 16:04)
> Ну что здесь можно предложить, кроме существующей реализации
> оператора?
Взять и честно проверить ВСЕГДА что же там на самом деле. Так, как это делается в случае, скажем, когда было бы написано
if TObject(btn) is TButton then
Неужели это невозможно?? Если да, по почему???
← →
Тимохов © (2004-07-14 16:09) [93]
> Неужели это невозможно?? Если да, по почему???
считаю, что это вполне возможно.
НО! Считаю, что это сделано правильно - не правильно описана дока.
← →
STYLE © (2004-07-14 16:10) [94]
> Неужели это невозможно?? Если да, по почему???
Да потому что смысла нет в такой проверке :)
← →
DiamondShark © (2004-07-14 16:12) [95]
> Тимохов © (14.07.04 16:05) [90]
Да ну?!
← →
Тимохов © (2004-07-14 16:13) [96]
> DiamondShark © (14.07.04 16:12) [95]
>
> > Тимохов © (14.07.04 16:05) [90]
>
> Да ну?!
у нас так разговор не выйдет.
я привел конкретное возражение про хелп, вы "да ну?"
что-то хотите сказать? :))
← →
DiamondShark © (2004-07-14 16:15) [97]
> Тимохов © (14.07.04 16:13) [96]
В каких случаях проверка выполняется при компиляции?
← →
Sergey Kamininski (2004-07-14 16:17) [98]Да, дока-таки да, способна ввести в заблуждение. Видимо, парни из Борланда не смогли предусмотреть, что is кто-то всерьез будет использовать подобным образом.
← →
Тимохов © (2004-07-14 16:17) [99]
> DiamondShark © (14.07.04 16:15) [97]
>
> > Тимохов © (14.07.04 16:13) [96]
>
> В каких случаях проверка выполняется при компиляции?
Вы с луны, того, свалились? Весь топик говорится об этом :)))))
пот напримерvar
a: TMyClass;
begin
a := pointer(any integer value <> 0);
if a is TMyClass всегда будет бедет true
end;
← →
Тимохов © (2004-07-14 16:19) [100]Если никто не против выскажу очередное свое резюме
Piter докопался до того, что описании is не соответсвует ее семантике (функциональности).
Кто против?
← →
DiamondShark © (2004-07-14 16:26) [101]
> Тимохов © (14.07.04 16:17) [99]
А в CPU посмотреть?
← →
Тимохов © (2004-07-14 16:27) [102]
> А в CPU посмотреть?
посмотрите...
← →
DiamondShark © (2004-07-14 16:29) [103]
> Тимохов © (14.07.04 16:19) [100]
> Кто против?
Я.
Могу переформулировать резюме:
Иногда интуитивные предположения могут не соответсвовать криво понимаемому описанию.
← →
Тимохов © (2004-07-14 16:30) [104]Вот в таком коде
type
TMyClass = class b: integer end;
procedure TForm1.Button4Click(Sender: TObject);
var
a: TMyClass;
begin
a := pointer(2134242);
if a is TMyClass then
showmessage("hi");
end;
строчкаif a is TMyClass then
равна0045468B 837DF800 cmp dword ptr [ebp-$08],$00
0045468F 740A jz +$0a
Т.е. просто проверка <> nil.
← →
Piter © (2004-07-14 16:30) [105]Cobalt © (14.07.04 14:37) [76]
Ты согласен, что Cobalt © (14.07.04 13:02) [67] - вполне разумные ограничения?
я согласен с твоим постом... но о каких ограничениях ты говоришь? Ты просто описал поведение компилятора Дельфи :)
И тут я не согласен с этим:
var1 is It"sClassTypeOrOneOfParentClassType,
то IsClass не вызывается - просто проверяется, assigned ли эта переменная
я тут считаю (хотя писал это уже 100 раз), что IsClass вызываться должен.
Если присваивать переменной фигню типа Pointer(bla-bla-bla) - это уже твоя головная боль - делай общего предка, и баста! (если хочешь нормально работать, а не воевать с классами)
не согласен насчет баста. То есть, согласен, конечно, нужно делать правильно. Но это не исключает вопроса почему IS ведет себя таким образом. Ведь приведения типа Pointer(bla-bla-bla) в Дельфи возможны. А если они возможны, то и IS должен это учитывать. Да, в каком-то смысле это защита от дурака. Но почему бы ее не сделать?
DiamondShark © (14.07.04 14:09) [75]
А теперь внимание, вопрос. Каким образом определить, сослался ли указатель на структуру RTTI, просто на какой-то кусок памяти, или вообще за пределы адресного пространства?
Ответ: никаким.
А вот это хороший вопрос. И ответ, имхо, неправильный.
Нужно просто вызвать IsClass :)
Если он вернет True - значит, это как раз структура RTTI. Если он вызывал AV - то значит нет.
Возможны, конечно, случаи, что в памяти будут случайные наборы байтов, которые в сумме образуют нужный код, который вернет true.... но это грубо говоря маловероятно :)
или вообще за пределы адресного пространства?
а вот это интересно. Как можно сослаться за пределы адресного пространства? Вроде как адреснео пространство 4 гигабайта. И указатель это четырехбайтовое целое, которые как раз может указывать в любом диапазоне от 0 до 4-х гигабайт. Как он может указывать за адресное пространство?
← →
Тимохов © (2004-07-14 16:30) [106]Иногда интуитивные предположения могут не соответсвовать криво написанному описанию.
← →
Тимохов © (2004-07-14 16:32) [107]
> Piter © (14.07.04 16:30) [105]
Не упосртвуйте, в том, что реализация здесь должна быть иная.
Вы нашли недочет в доке - не более.
Дело за малым - убедиль алмазную укулу :))))
← →
DiamondShark © (2004-07-14 16:34) [108]
> Тимохов © (14.07.04 16:27) [102]
>
> > А в CPU посмотреть?
>
> посмотрите...
А вы испытаете мазохистское удовольствие от тыканья вас носом?
Тоды ой. Смотрите:z := pointer(123);
mov EAX, $0000007b
if z is zzz then ShowMessage("dfff");
test EAX, EAX
jz XXX
mov EAX, XXXXXXXX
call ShowMessage
<-- адрес XXX здесь
...
← →
Тимохов © (2004-07-14 16:37) [109]
> DiamondShark © (14.07.04 16:34) [108]
ой а, что это? мне умные дяди говорили, что оссеблер. Да?
у... как круто...
----------
В чем проблема? Вы видите в своем коде вызов IsClass иши InheritsFrom. Имеено об этом я и говорю: в докуме есть слово runtime, вы же наглядно показали, что никаких runtime проверок нет - все проуверки (т.е. вызов isclass или inheritsfrom) убраны еще в comilertime.
Есть предложение. Опишите строчек пять, во что вы меня хотите тыкнуть - есть ощущение, что мы говорим о разных вещах.
← →
Anatoly Podgoretsky © (2004-07-14 16:39) [110]Вообще то адресное пространство для x86 равно 2^48, Микрософт на данный момент поддерживает 64 гб
← →
Sergey Kamininski (2004-07-14 16:39) [111]Черт, а забавный вообще-то код компилируется из такого:
var
btn: TButton;
begin
btn := Pointer(TEdit.Create(nil));
if btn is TButton then
begin
TButton(btn).Parent := self;
Btn.Caption := "111";
Btn.Cancel := True;
end;
end;
Это ж надо так компилятор затуркать. На самом деле интересно выходит.
Любопытствующие могут наблюдать, какBtn.Caption := "111";
транслируются в вызовTControl.SetText
, с соответствующим результатом,а также предлагаю разобраться, куда пишется $01 вместоBtn.Cancel := True
.
Забавно.
← →
Anatoly Podgoretsky © (2004-07-14 16:39) [112]Anatoly Podgoretsky © (14.07.04 16:39) [110]
Поправка 2^46
← →
Тимохов © (2004-07-14 16:39) [113]прикольно - обсуждение разделилось на 3 лагеря.
1. is работате верно - DimondShark
2. is работает верно, но неверно сделана дока - я
3. is работает неверно - piter.
:))))
← →
DiamondShark © (2004-07-14 16:45) [114]
> Тимохов © (14.07.04 16:37) [109]
А вы видите в доке обязательство вызвать IsClass?
А вот я вижу проверку на nil.
В полном соответсвии с докой.
← →
Sergey Kamininski (2004-07-14 16:46) [115]4. В доке есть уточняющая оговорка. Впрочем, не слишком убедительная. Я. :-)
← →
Тимохов © (2004-07-14 16:48) [116]
> DiamondShark © (14.07.04 16:45) [114]
>
> > Тимохов © (14.07.04 16:37) [109]
>
> А вы видите в доке обязательство вызвать IsClass?
> А вот я вижу проверку на nil.
> В полном соответсвии с докой.
меня смущает слово runtime. согласитесь, что от такого описания ждешь другой семантики.
Хотя повторюсь, я не считаю семантику неверной - она удовлетворяет задачам на 100 процентов.
← →
ИдиотЪ (2004-07-14 16:50) [117]мне тоже кажется, что оператор
btn := Pointer(TEdit.Create(nil))
является некорректным и даже опасным, соответственно расплата может быть незамедлительно или позже. Тем более нигде не учат такому, а превращать Дельфи в жесткую систему контроля - параноя! А если начать изменять в любом месте с помощью указателей данные и чтоб Дельфи это потом отследила некорректность, на что это будет похоже?
Попробуйте для разнообразия такое:
if TButton(Edit) is TButton then
ShowMessage("Неуж-то кнопка?");
← →
nikkie © (2004-07-14 16:51) [118]>Тимохов
>Дело за малым - убедиль алмазную укулу :))))
ты чересчур оптимистичен. :))
← →
Григорьев Антон © (2004-07-14 16:51) [119]
> Piter © (14.07.04 13:36) [69]
> Sergey Kaminski (14.07.04 6:32) [43]
> Не смущает, что в таком случае AV будет всегда? Независимо
> "от версии Делфи". И количества итераций
>
> НЕ смущает! Потому что ты указал ссылку НЕ на экземпляр
> класса, а на ЧЕРТ ЗНАЕТ ЧТО! Получил AV в программе! Задумался,
> оттрасировал программу, нашел ошибку, понял, исправил!
>
> А вот тебя не смущает, что "ЛОГИЧНЫЙ" Is вернет TRUE в этом
> случае? Не кажется, что логика программы может пойти неправильным
> путем? Ибо указатель на хрен знает что признается указателем
> на TButton?
Если указатель указывает непонятно на что, то результат любых операций над ним непредсказуем. Это следует из внутреннего представления указателя в Delphi. Можно было бы выбрать другое внутреннее представление, защищающее от таких ошибок, но это привело бы к уменьшению гибкости и быстродействия. Та форма представления указателя, которая выбрана в Delphi, обеспечивает максимальную скорость и гибкость, но взамен требует от программиста, чтобы он сам следил за корректностью указателей. Если тебя интересует эта тема, могу порекомендовать пару книжек (печатных; электронных не знаю), в которых обзорно рассмотрены разные подходы к конструированию и реализации языков программирования. Оттуда, в частности, можно узнать, что указатель может быть не похож на то, что мы привыкли называть указателем.
И советую подумать над такой проблемой: как можно в принципе реализовать то, чтобы после Free is или любое другое действие гарантированно бы приводило к AV. Без твоих конкретных предложений по реализации считаю дальнейший разговор на эту тему бессмысленным.
> Тимохов © (14.07.04 15:16) [81]
> для реализации поведения Антона есть inheritsfrom.
Моё поведение ни от каких inheritsfrom не зависит!!! Я обладаю свободой воли!!! :)))
> Тимохов © (14.07.04 16:19) [100]
> Если никто не против выскажу очередное свое резюме
>
> Piter докопался до того, что описании is не соответсвует
> ее семантике (функциональности).
>
> Кто против?
Согласен. И, более того, считаю вредным выяснять, то ли поведение правильное, а описание нет, то ли, наоборот, описание правильное, а поведение - нет. Не соответсвует - и всё тут. Без дальнейших комментариев.
← →
DiamondShark © (2004-07-14 16:53) [120]
> Piter © (14.07.04 16:30) [105]
> DiamondShark © (14.07.04 14:09) [75]
> А теперь внимание, вопрос. Каким образом определить, сослался
> ли указатель на структуру RTTI, просто на какой-то кусок
> памяти, или вообще за пределы адресного пространства?
> Ответ: никаким.
>
> А вот это хороший вопрос. И ответ, имхо, неправильный.
>
> Нужно просто вызвать IsClass :)
> Если он вернет True - значит, это как раз структура RTTI.
> Если он вызывал AV - то значит нет.
>
> Возможны, конечно, случаи, что в памяти будут случайные
> наборы байтов, которые в сумме образуют нужный код, который
> вернет true.... но это грубо говоря маловероятно :)
Не надо грубо говорить, обычно от этого фигня получается.
Ты предлагаешь реализовать оператор в расчёте на то, что авось куда-то попадём? Ню-ню...
А потом подумай. Большая часть динамической памяти -- это как раз действительные экземпляры и обрывки экземпляров объектов.
И как тут твоё "маловероятно"?
> или вообще за пределы адресного пространства?
>
> а вот это интересно. Как можно сослаться за пределы адресного
> пространства? Вроде как адреснео пространство 4 гигабайта.
> И указатель это четырехбайтовое целое, которые как раз может
> указывать в любом диапазоне от 0 до 4-х гигабайт. Как он
> может указывать за адресное пространство?
Уймись, ламерок.
За одно твоё предложение тыкать куда попало по мусорному указателю тебя надо подвергать эвтаназии.
← →
Григорьев Антон © (2004-07-14 16:56) [121]
> Тимохов © (14.07.04 16:39) [113]
> прикольно - обсуждение разделилось на 3 лагеря.
>
> 1. is работате верно - DimondShark
> 2. is работает верно, но неверно сделана дока - я
> 3. is работает неверно - piter.
>
> :))))
Ха-ха! А я ни в один из этих лагерей не попал - см. [119]
← →
DiamondShark © (2004-07-14 16:57) [122]
> Тимохов © (14.07.04 16:48) [116]
Интересно, а от оператора "+" вы какой семантики ждёте?
Будете тоже громко протестовать, что строка
a := 1 + 2;
компилируется в
mov EAX, 3
или как?
← →
Sergey Kamininski (2004-07-14 16:58) [123]Кстати, помните первый пост:
Вылавливал баг в своей программе и обнаружил интереснейшую вещь. Окаывается, оператор IS вызывает Acees Violation при определенных условиях!
При таком подходе этаких "БАГОВ" будет - ой.
;)
← →
DiamondShark © (2004-07-14 17:01) [124]
> Тимохов © (14.07.04 16:39) [113]
Кстати, а откуда вы взяли, что is работает верно, если дока, по-вашему, написана неверно? Что-то тут с логикой не то...
← →
Тимохов © (2004-07-14 17:04) [125]
> Григорьев Антон © (14.07.04 16:51) [119]
> Не соответсвует - и всё тут. Без дальнейших комментариев.
На все сто (в смысле согласен)
← →
Anatoly Podgoretsky © (2004-07-14 17:05) [126]Var Type of TButton is TButton не требует проверки в run time, кроме проверки на nil, а вот Var of other Type TButton is TButton требует
← →
Тимохов © (2004-07-14 17:05) [127]
> DiamondShark © (14.07.04 17:01) [124]
>
> > Тимохов © (14.07.04 16:39) [113]
>
> Кстати, а откуда вы взяли, что is работает верно, если дока,
> по-вашему, написана неверно? Что-то тут с логикой не то...
вы типа пост, похоже не целиком читали.
почему я считаю, что is работает верно я наверное раз 5 объяснял :)))
← →
Тимохов © (2004-07-14 17:07) [128]
> DiamondShark © (14.07.04 17:01) [124]
А в оббщем я уже соглсился с утвержденем Антона Григорьева: "Не соответсвует - и всё тут. Без дальнейших комментариев."
Для меня это есть личный вывод из топика.
Т.е. считайте, что я несколько изменил свое мнение в сторону универсальности. Трактуйте как хотите. :))))
← →
Piter © (2004-07-14 17:16) [129]Удалено модератором
Примечание: Намеки на умственное развитие допустимы по отношению к автору ветки и недопустимы автором
← →
Sandman25 © (2004-07-14 17:16) [130]
type
Boolean = (False, True, Null);
TSuperObject = class
private
FIsAlive: Boolean;
public
property IsAlive: Boolean read FIsAlive;
constructor Create;
destructor Destroy; override;
function IsClass(AClass: TClass): Boolean;
end;
procedure TForm1.FormCreate(Sender: TObject);
var
Super: TSuperObject;
begin
Super := nil;
ShowMessage(IntToStr(Ord(Super.IsClass(TSuperObject))));
Super := TSuperObject.Create;
ShowMessage(IntToStr(Ord(Super.IsClass(TSuperObject))));
Super.Free;
ShowMessage(IntToStr(Ord(Super.IsClass(TSuperObject))));
end;
{ TSuperObject }
constructor TSuperObject.Create;
begin
FIsAlive := True;
end;
destructor TSuperObject.Destroy;
begin
FIsAlive := False;
end;
function TSuperObject.IsClass(AClass: TClass): Boolean;
begin
if Assigned(Self) then
if (IsAlive = True)then
Result := Boolean(Self is AClass)
else
Result := Null
else
Result := Null
end;
Показывает 2 (Null - объект еще не создан), 1 (True - объект создан и доступен), 2 (Null - объект был создан, а затем уничтожен).
Во избежание AV следует заменить Result := Boolean(Self is AClass)
на
try
Result := Boolean(Self is AClass)
except
Result := Null
end;
← →
DiamondShark © (2004-07-14 17:20) [131]
> Тимохов © (14.07.04 17:07) [128]
Какой такой универсальности?
← →
Тимохов © (2004-07-14 17:20) [132]
> А знаешь, чтобы тебе копать в этой области - тебе тоже не
> мешает изучить представленные тобой же материалы.
я привел материалы, которые изучил сам
они мне позволяют отвечать на твои возражения про везение.
Причем здесь значок?
Моя позиция однозначно и непоколебимо закреплена в 128.
Что же делать, если сменил задумался о чем-то и пришлось изменить свое мнение? На то он и форум.
← →
Тимохов © (2004-07-14 17:22) [133]
> Какой такой универсальности?
Процитирую слова Антона Григорьва из 119
"И, более того, считаю вредным выяснять, то ли поведение правильное, а описание нет, то ли, наоборот, описание правильное, а поведение - нет".
Т.е. универсальность в том, чтобы не выносить суждения в той области, где правдны не найдешь - сколько людей, столько и мнений.
← →
ИдиотЪ (2004-07-14 17:24) [134]всем сомневающимся насчет is - пользуйтесь своей версией и тогда может быть лет через 10 Borland признает ваши нелегкие начинания!
← →
Григорьев Антон © (2004-07-14 17:24) [135]
> а вот это интересно. Как можно сослаться за пределы адресного
> пространства? Вроде как адреснео пространство 4 гигабайта.
> И указатель это четырехбайтовое целое, которые как раз может
> указывать в любом диапазоне от 0 до 4-х гигабайт. Как он
> может указывать за адресное пространство?
Это так называемое виртуальное адресное пространство. Оно разбито на блоки по 4 кб (начиная с Windows 2000 - по 64 кб), и каждый такой блок может:
а) быть сопоставленным с блоком физической памяти;
б) быть сопоставленным с блоком, выгруженным на диск;
в) не быть ни с чем сопоставленным.
Когда указатель указывает на блок типа "в", и мы пытаемся что-то с ним сделать, то возникает AV.
← →
Sergey Kamininski (2004-07-14 17:28) [136]2 [129]
это между прочим не черт знает что, а экземпляр TEdit!
Нет, уважаемый, это никакой не TEdit, а TEdit, приведенный к TButton по твоей настойчивой просьбе. И, говоря иносказательно: "Ты ведь просил компилятор обходиться с TEdit как с TButton -- вот он и исполнил твою просьбу ПОЛНОСТЬЮ". А чего же ты хотел ;)
← →
Piter © (2004-07-14 17:28) [137]DiamondShark © (14.07.04 16:45) [114]
А вы видите в доке обязательство вызвать IsClass?
А вот я вижу проверку на nil.
А что еще означает динамическая проверка?!?!
А вы видите в доке описание, что будет ТОЛЬКО лишь проверка на nil. Вам не кажется, что для этого есть совсем другая функция - assigned? Или для вас абсолютно естесственно, что IS и ASSIGNED делают одно и тоже?
nikkie © (14.07.04 16:51) [118]
Ты чего, уже вернулся из отпуска? Ну и как оно? :)))
← →
Тимохов © (2004-07-14 17:30) [138]
> Piter © (14.07.04 17:28) [137]
> А что еще означает динамическая проверка?!?!
в этом полностью тебя поддерживаю.
а вот тут
> А вы видите в доке описание, что будет ТОЛЬКО лишь проверка
> на nil. Вам не кажется, что для этого есть совсем другая
> функция - assigned? Или для вас абсолютно естесственно,
> что IS и ASSIGNED делают одно и тоже?
имхо тебя не туда понесло.
----------------------------------
Я в патрии Антона Григорьева - is описан неверно! И баста - никаких если, никаких но. Нас уже двое!
← →
DiamondShark © (2004-07-14 17:32) [139]Удалено модератором
Примечание: На три дня, не надо опускаться до такой степени
← →
Anatoly Podgoretsky © (2004-07-14 17:32) [140]Такие вещи голосованием не решаются.
← →
Тимохов © (2004-07-14 17:34) [141]
> DiamondShark © (14.07.04 17:32) [139]
давайте жить дружно!
он же прав про compile time - кое что вырезается на стадии именно компиляции. Ну мы же это и обсуждаем зачем так, типа грубо.
← →
nikkie © (2004-07-14 17:35) [142]>Ты чего, уже вернулся из отпуска? Ну и как оно? :)))
вернулся... хорошо, но мало :))
← →
DiamondShark © (2004-07-14 17:35) [143]
> Piter © (14.07.04 17:28) [137]
Ты непроходимо туп. Сделай полезное дело -- сдохни.
← →
Григорьев Антон © (2004-07-14 17:36) [144]
> DiamondShark © (14.07.04 17:32) [139]
Был бы я модератором - ты бы за такое хамство недельку в R/O посидел.
← →
Sergey Kamininski (2004-07-14 17:43) [145]Встретились, поговорили...
← →
DiamondShark © (2004-07-14 17:45) [146]
> Тимохов © (14.07.04 17:34) [141]
Нет. Это тупое животное должно было умереть сразу, как написало проверку после разрушения экземпляра.
← →
KSergey © (2004-07-14 17:51) [147]> [139] DiamondShark ©
Ты бы лучше написал подробно, почему Тихомонов не прав, когда в ассемблерном коде только проверка на нил.
Подгорецкий хоть написал.
А недоумками обозвать - большого ума не надо.
Уперся, блин, у все тут... Типа умный самый.
PS
Прошу прощения у окружающих, но считаю, что товарисч ведет себя здесь уже совершенно некорректно.
← →
Тимохов © (2004-07-14 17:51) [148]
> DiamondShark © (14.07.04 17:45) [146]
дело ваше...
← →
Тимохов © (2004-07-14 17:52) [149]
> Ты бы лучше написал подробно, почему Тихомонов не прав
а это кто такой? Я? :)))
Лучше уж вы напишите, в чем я не прав.
От товрисча конструктива похоже не дождешься
← →
Piter © (2004-07-14 17:53) [150]Григорьев Антон © (14.07.04 16:51) [119]
> А вот тебя не смущает, что "ЛОГИЧНЫЙ" Is вернет TRUE в этом
> случае? Не кажется, что логика программы может пойти неправильным
> путем? Ибо указатель на хрен знает что признается указателем
> на TButton?
Если указатель указывает непонятно на что, то результат любых операций над ним непредсказуем. Это следует из внутреннего представления указателя в Delphi. Можно было бы выбрать другое внутреннее представление, защищающее от таких ошибок, но это привело бы к уменьшению гибкости и быстродействи
Э-э-э, Антон, тебя не туда понесло. Я и не говорил, что IS должна работать корректно, если объект уничтожен.
Я про то, что если:var sc: TSameClass
...
sc := Pointer(5555);
if sc is TSameClass
так вот я за то, чтобы здесь был AV.
А Sergey Kaminski утверждает, что существующее поведение правильно и что так и надо, что оператор IF выполнится.
Григорьев Антон © (14.07.04 16:51) [119]
И, более того, считаю вредным выяснять, то ли поведение правильное, а описание нет, то ли, наоборот, описание правильное, а поведение - нет. Не соответсвует - и всё тут. Без дальнейших комментариев
Согласен. И вредно потому, что как я понял это будет вечный флейм. Короче, мы придумали новую Hole WarL
Intel vs AMD
Windows vs UNIX
Delphi vs VC++
...
IS vs Корректность :)
Григорьев Антон © (14.07.04 16:51) [119]
И советую подумать над такой проблемой: как можно в принципе реализовать то, чтобы после Free is или любое другое действие гарантированно бы приводило к AV
зачистка памяти. То есть, обнуление памяти, где распологался объект. А не просто объявление этой памяти свободной.
DiamondShark © (14.07.04 16:53) [120]
А потом подумай. Большая часть динамической памяти -- это как раз действительные экземпляры и обрывки экземпляров объектов.
И как тут твоё "маловероятно"?
Да-а-а? Адресное пространство 4 гигабайта. Большая часть памяти - это как минимум больше половины. То есть, более двух гигабайт занято обрывками классов? Гы... увольте
Уймись, ламерок.
За одно твоё предложение тыкать куда попало по мусорному указателю тебя надо подвергать эвтаназии
Строго прошу тебя, DiamondShark, больше в эту ветку не заходить. Да, это твое право писать сюда, ветка - часть форума. Но я тебя прошу как человека больше сюда не заглядывать.
Заранее спасибо.
Тимохов © (14.07.04 17:20) [132]
Что же делать, если сменил задумался о чем-то и пришлось изменить свое мнение? На то он и форум
я бы сказал на то она и жизнь. Я вообще считаю абсолютно нормальным, что человек меняет свою точку зрения, лишь бы это не происходило бы очень часто. Гораздо лучше исправить свое мнение на верное, чем бычить и остаивать СВОЕ, но неверное мнение...
Григорьев Антон © (14.07.04 17:24) [135]
а-а-а, понял. Спасибо за разъяснение - я это знаю. Просто под адресным пространством у меня ассоциируется ВАП. Наверное, это неправильно.
Sergey Kamininski (14.07.04 17:28) [136]
Нет, уважаемый, это никакой не TEdit, а TEdit, приведенный к TButton по твоей настойчивой просьбе
А чем внутренне отличается TEdit "натуральный" от TEdit приведенного? :)) У него что, какие-то поля не так заполнены, вообще, он хоть байтом будет отличаться от приведенного? :) Собственно говоря, приводят не сами внутренние структуры компонентов (это было бы невозможно), а просто ссылки на них. А ссылка - это что? Обычное 4-х байтовое целое.
← →
Piter © (2004-07-14 17:55) [151]Я был о DiamondShark лучшео мнения... да, жаль.
← →
Тимохов © (2004-07-14 17:56) [152]
> зачистка памяти. То есть, обнуление памяти, где распологался
> объект. А не просто объявление этой памяти свободной.
Не гони. К тому же ничего не мешает это тебе реализовать самому. Почитай TObject.FreeInstance. Нет проблем:)
← →
app © (2004-07-14 17:56) [153]Все ветку закрываю, так как пошла личная перепалка
Страницы: 1 2 3 4 вся ветка
Текущий архив: 2004.08.01;
Скачать: CL | DM;
Память: 1.03 MB
Время: 0.04 c