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

Вниз

Кто-нибудь сможет сходу определить причину ошибки? :)   Найти похожие ветки 

 
Piter ©   (2004-10-04 23:10) [0]

Вот такой я маленький тест придумал... Кто сможет без Дельфей объяснить следующую ситуацию:

Такой код работает:

procedure TForm1.Button1Click(Sender: TObject);
var
 Edit: TEdit;
begin
 with Edit do
   begin
     Edit := TEdit.Create(self);
     Parent := self;
   end;
end;


А вот такой код НЕ работает:

procedure TForm1.Button1Click(Sender: TObject);
var
 ArrayEdit: array of TEdit;
begin
 setlength(ArrayEdit, 1);
 with ArrayEdit[0] do
   begin
     ArrayEdit[0] := TEdit.Create(self);
     Parent := self;
   end;
end;


Вопрос - почему? :)

P.S. На ум приходит очевидный ответ... но почему же первый пример работает?


 
panov ©   (2004-10-04 23:13) [1]

Всё просто...


 
panov ©   (2004-10-04 23:14) [2]

Edit: TEdit - обрабатывает компилятор.


 
Ломброзо ©   (2004-10-04 23:20) [3]

> Parent := self;

чей блин парент?


 
Piter ©   (2004-10-04 23:24) [4]

panov ©   (04.10.04 23:14) [2]
Edit: TEdit - обрабатывает компилятор


не понял твою идею :)
Что значит обрабатывает компилятор? Типа другие строки компилятор не обрабатывает? :)


 
_silver ©   (2004-10-04 23:30) [5]


>var
>  ArrayEdit: array of TEdit;

Может я и не прав, но это динамический массив.
Надо SetLength


 
jack128 ©   (2004-10-04 23:33) [6]

Тя разговор с GuAV навел на эти эксперементы?? Ну так у него(у GuAV) в анкете есть ответ на твой вопрос. Нужно лищь глянуть в окно CPU..


 
_silver ©   (2004-10-04 23:35) [7]

Извиняюсь.
ArrayEdit[0].Parent := self;


 
_silver ©   (2004-10-04 23:39) [8]


>_silver ©   (04.10.04 23:30) [5][Ответить]
>
>>var
>>  ArrayEdit: array of TEdit;
>
>Может я и не прав, но это динамический массив.
> Надо SetLength

Ещё раз прошу прошения.


 
Cobalt ©   (2004-10-04 23:40) [9]

Вообще-то код с логической точки зрения некорректный - если компилятор и может (в принципе), то с логической точки зрения надо сначала проинициализировать переменную, а потом уже делать
with AlreadyInitialisedClassVariable do


 
Cobalt ©   (2004-10-04 23:42) [10]

пардон, не закончил фразу - компилятор может, в принципе, разрулить такую ситуацию.
Но разработчики переложили это на плечи программистов.


 
Ломброзо ©   (2004-10-04 23:47) [11]

Cobalt ©   (04.10.04 23:40) [9]
ИМХО под локальные переменные просто выделяется кусок стека. А посему при вызове делать инициализацию этого куска нулём - это лишний такт. Вот пущай программист сам обнуляет, если ему нужно.


 
jack128 ©   (2004-10-04 23:48) [12]

Ломброзо ©   (04.10.04 23:47) [11]
ИМХО под локальные переменные просто выделяется кусок стека


не всегда. Пример с edit"ом(первый) тому подтверждение


 
_silver ©   (2004-10-04 23:50) [13]

Работает так:
with ArrayEdit[0] do
  begin
    ArrayEdit[0] := TEdit.Create(self);
    ArrayEdit[0].Parent := self;
  end;
и так:
ArrayEdit[0] := TEdit.Create(self);
with ArrayEdit[0] do
  begin
    Parent := self;
  end;


 
_silver ©   (2004-10-04 23:52) [14]

Это я ктому, что компилятор может ещё не знать о ArrayEdit[0].Parent в первом варианте.


 
_silver ©   (2004-10-04 23:57) [15]

Т.е. конструкция width ArrayEdit[0] ещё не определена.


 
Ломброзо ©   (2004-10-04 23:58) [16]

jack128 ©   (04.10.04 23:48) [12]

А что там в первом примере? Указатель нулю равен? дык это просто повезло.


 
jack128 ©   (2004-10-05 00:04) [17]

Если с асм"ом не очень, то озвучу явно - в первом примере переменной Edit вообще не существует. И строка with Edit компилятором вообщ игнорируется. Для обращения к SetParent используется результат TEdit.Create(Self)

Во втором примере начало в регистры проца закачивается ArrayEdit[0] (мусор)(эквивалент with ArratEdit[0] do), потом в память записывается результат  TEdit.Create(Self), а потом уже берется наша копия ArrayEdit[0] (которая мусор)  и используется для SetParent
Ломброзо ©   (04.10.04 23:58) [16]
Указатель нулю равен? дык это просто повезло.

нету указателя как такового. Нету переменной Edit вообще. вот для такого кода

:

procedure TForm1.Button1Click(Sender: TObject);
var
Edit: TEdit;
begin
with Edit do
  begin
    Edit := TEdit.Create(self);
    Parent := self;
    Top := 10;
  end;
end;

то что храниться в esi можно назвать переменной Edit, но не для примера Piter"a


 
Ломброзо ©   (2004-10-05 00:14) [18]

Аспасиба. Я действительно в ассемблере мало, но на грабли с неинициализированным указателем на объект в теле функции в ++, как и всякому нормальному человеку, наступать приходилось )


 
GuAV ©   (2004-10-05 00:31) [19]

А теперь версия ответа на этот вопрос от GuAV :)
Откомпилируйте обе версии.
Слева вы видете то что попало в конечный ехе синими кружечками отмечено.
в случае с массивом with попало в ехе. это как бы создало локальную переменную.
в другом случае Edit и есть та переменная

регистры или память не важно ({$O-} - и будет оно в стеке), но Ctrl+Alt+ тут конечно проясняет.


 
GuAV ©   (2004-10-05 00:33) [20]


>  Ctrl+Alt+ тут конечно проясняет.

Ctrl+Alt+С естественно, не Del :)


 
_silver ©   (2004-10-05 00:47) [21]

О чём вы рассуждаете?
ArrayEdit: array of TEdit - дин масив.
На этапе  
setlength(ArrayEdit, 1);
with ArrayEdit[0] do
ещё не известно что будет находиться в ArrayEdit[0].
Вся конструкция
with ArrayEdit[0] do
  begin
    ArrayEdit[0] := TEdit.Create(self);
    Parent := self;
  end;
просто не коректна.


 
jack128 ©   (2004-10-05 01:02) [22]

_silver ©   (05.10.04 0:47) [21]
ну и что?? with Edit do - тоже не определен, а тем немение работает.
ГуАВ все правельно объяснил.


 
Piter ©   (2004-10-05 01:10) [23]

jack128 ©   (04.10.04 23:33) [6]
лищь глянуть в окно CPU..


ну дык. Только вот:


> Кто сможет без Дельфей объяснить следующую ситуацию


:)))

Я вот о чем подумал. Отстранимся от ассемблера.
С точки зрения разработчика, получается, что в первом случае под with подразумевается именно реальный текущий Edit.
То есть, можно написать:

procedure TForm1.Button1Click(Sender: TObject);
var
Edit: TEdit;
begin
with Edit do
  begin
    Edit := TEdit.Create(self);
    Free;
    Edit := TEdit.Create(self);
    Parent := self;
  end;
end;


И все будет ок. В последней строчке Parent := self; имеется в виду именно реальный Edit. Не тот Edit который был на начале With (мусор). И не тот Edit, который был создан первично. А именно актуальный на текущий момент Edit. Вот то, что показывает Watch List [Pointer(Edit)] - к тому и будет обращение .
Получается аналог этого кода:

procedure TForm1.Button1Click(Sender: TObject);
var
Edit: TEdit;
begin
    Edit := TEdit.Create(self);
    Edit.Free;
    Edit := TEdit.Create(self);
    Edit.Parent := self;
end;


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

procedure TForm1.Button1Click(Sender: TObject);
var
ArrayEdit: array of TEdit;
begin
setlength(ArrayEdit, 1);
with ArrayEdit[0] do
  begin
    ArrayEdit[0] := TEdit.Create(self);
    Parent := self;
  end;
end;


Должен быть эквивалентен:

procedure TForm1.Button1Click(Sender: TObject);
var
ArrayEdit: array of TEdit;
begin
setlength(ArrayEdit, 1);
    ArrayEdit[0] := TEdit.Create(self);
    ArrayEdit[0].Parent := self;
end;


Иначе говоря, если есть обращение:

with SomeClass do
 SomeMethod;


то если у SomeClass есть метод SomeMethod, то такая конструкция ничем не должна отличаться от простого:

SomeClass.SomeMethod

Но во втором случае компилятор не так делает. Он не тупо обращается к экземпляру класса. Он обращается туда, куда указывал ArrayEdit[0] на начало with.
Ведь with не что иное как просто упрощения записи, чтобы было понятнее.

То есть, если мы пишем:

with SomeClass do
 begin
   SomeMethod1;
   SomeMethod2;
   SomeMethod3;
   SomeMethod4;
 end;


То мы как бы можем рассчитывать, что это тоже самое, что и такой код:

SomeClass.SomeMethod1;
SomeClass.SomeMethod2;
SomeClass.SomeMethod3;
SomeClass.SomeMethod4;


А получается, что не совсем так...

Во втором случае мне кажется компилятор ведет себя немного не так, как нужно. Кто как считает? :)

P.S. Сейчас мне кто-нибудь точно припомнит IS :)))

P.S.S. Сам сейчас прочитал, что написал... блин, надо учиться излагать мысли, как-то все коряво получилось.


 
Piter ©   (2004-10-05 01:11) [24]

_silver ©   (05.10.04 0:47) [21]
О чём вы рассуждаете?
ArrayEdit: array of TEdit - дин масив.
На этапе  
setlength(ArrayEdit, 1);
with ArrayEdit[0] do
ещё не известно что будет находиться в ArrayEdit[0].
Вся конструкция
with ArrayEdit[0] do
 begin
   ArrayEdit[0] := TEdit.Create(self);
   Parent := self;
 end;
просто не коректна.


Ладно, получается что:

"О чём вы рассуждаете?
Edit: TEdit - это экземпляр класса
На этапе  
with Edit do
ещё не известно что будет находиться в Edit.
Вся конструкция
with Edit do
 begin
   Edit := TEdit.Create(self);
   Parent := self;
 end;
просто не коректна."

Только вопрос - почему работает то? :)


 
_silver ©   (2004-10-05 01:17) [25]

Дин масив ссылок на что-то типа TEdit допустим.
with ArrayParent[0] - ожидается использование объекта типа TEdit, но ещё не создан.
Поэтому в блоке begin .. end свойство Parent(класса TEdit) неизвестно.

З.Ы.
 Это тоже что сказал GuAV тока с объяснением.


 
Knight ©   (2004-10-05 01:19) [26]

Не знаю как вы, а я всегда сначала делаю Create, а только после этого уже юзаю with...


procedure TForm1.Button1Click(Sender: TObject);
var
ArrayEdit: array of TEdit;
begin
setlength(ArrayEdit, 1);
ArrayEdit[0] := TEdit.Create(self);
with ArrayEdit[0] do begin
  Parent := self;
end;
end;


 
GuAV ©   (2004-10-05 01:20) [27]

Если with использованна с переменной, полем записи, то то что в with не требует вычислений и with вносит чисто синтаксические изменения.

Если with использованна с функцией, методом класса, и т.д. то то что в with требует вычислений, результат которых фактически заносится в новую переменную (которая в прочем может быть и в регистрах - но это уже следствие оптимиации).


> То мы как бы можем рассчитывать, что это тоже самое, что
> и такой код:

нет. но к записи это применимо.


 
jack128 ©   (2004-10-05 01:22) [28]

Piter ©   (05.10.04 1:10) [23]
Piter ©   (05.10.04 1:10) [23]
То есть, если мы пишем:

with SomeClass do
begin
  SomeMethod1;
  SomeMethod2;
  SomeMethod3;
  SomeMethod4;
end;

То мы как бы можем рассчитывать, что это тоже самое, что и такой код:

SomeClass.SomeMethod1;
SomeClass.SomeMethod2;
SomeClass.SomeMethod3;
SomeClass.SomeMethod4;

А получается, что не совсем так...

Как я понял из GuAV ©   (05.10.04 0:31) [19] из асм"а реально with SameVar do делает следующее

для кода

begin
 with SameVar do
 begin
   DoSamething1;
   DoSamething2;
   DoSamething3;
 end;
end;

компилятор генерит примерно следующее
для переменных в дин памяти:

var
 LocalVar: TSameType;
begin
 LocalVar := SameVar;
 LocalVar.DoSamething1;
 LocalVar.DoSamething2;
 LocalVar.DoSamething3;
end;

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

Piter ©   (05.10.04 1:10) [23]
> Кто сможет без Дельфей объяснить следующую ситуацию

Я бы ответил (я собственно так и ответил) не правельно, насчет оптимизации с выкидыванием ненужного Edit"a


 
GuAV ©   (2004-10-05 01:29) [29]


> для переменных в дин памяти:

Не только в дин. памяти, см. [27] .
Хороший пример
with MyArray[Random(5)] do
begin
 A:=5; B:=7;
end;
не то же что
MyArray[Random(5)].A:=5;
MyArray[Random(5)].B:=7;

но если заменить Random(5) на 5, то with не делает разницы.


 
_silver ©   (2004-10-05 01:35) [30]

GuAV ©   (05.10.04 1:29) [29]
Если MyArray : array of recor a : Integer; b : Integer; end;
..
with MyArray[Random(5)] do
begin
A:=5; B:=7;
end;
то еррор, как раз о то о чём говорил я.


 
GuAV ©   (2004-10-05 02:10) [31]

я имел ввиду стат массив.


 
Ihor Osov'yak ©   (2004-10-05 02:43) [32]

> Кто-нибудь сможет сходу определить причину ошибки? :)

Корень ошибки - в упорном нежелании обращать внимание на хинты и варнинги компилятора.

Зы. странно, что борланды вообще такую конструкцию считают синтастически допустимой...


 
1008 ©   (2004-10-05 09:14) [33]

Объявить массив глобально - должно работать, во всяком случае у меня подобные конструкции работают. Правда никогда не пробовал в качестве предка задавать сам компонент.


 
Fay ©   (2004-10-05 09:18) [34]

2 1008 ©   (05.10.04 09:14) [33]

> Правда никогда не пробовал в качестве предка задавать сам
> компонент.

Это Вы о чём?


 
1008 ©   (2004-10-05 09:28) [35]

Fay ©  (05.10.04 09:18) [34]

я делаю так:

var
RichEditArray:array of TRichEdit;

...

Procedure ...
var
i,n:integer;
begin
...
SetLehgth(RichEditArray,n);
for i:=0 to n-1 do begin
 RichEditArray[i]:=TRichEdit.Create(Self);
 RichEditArray[i].Parent:=Panel;//к примеру
end;


 
Fay ©   (2004-10-05 09:31) [36]

Как Вы делаете я понял. Но в пику чему этот пример?


 
SergP.   (2004-10-05 09:35) [37]

Могу конечно ошибиться, так как сейчас не могу запустить Delphi и поэкспериментировать с обоими примерами, а также попробовать статический массив.

with ArrayEdit[0]

Но имхо здесь автор сабжа вместо элемента массива получает указатель на сам массив.


 
1008 ©   (2004-10-05 09:40) [38]

Fay ©  (05.10.04 09:31) [36]

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

Piter ©  (04.10.04 23:10)


А вот такой код НЕ работает:

procedure TForm1.Button1Click(Sender: TObject);
var
ArrayEdit: array of TEdit;
begin
setlength(ArrayEdit, 1);
with ArrayEdit[0] do
 begin
  ArrayEdit[0] := TEdit.Create(self);
  ArrayEdit[0].Parent := self;
 end;
end;


вот так работает, хотя это уже указали


 
Fay ©   (2004-10-05 09:45) [39]

Вы, видимо, думаете, что в качестве Self выступает ArrayEdit[0]? Уверен, что это не так, что Self в данном случае - экземпляр TForm1.


 
SergP.   (2004-10-05 09:46) [40]


>  [37] SergP.   (05.10.04 09:35)


Все-таки я ошибся.
Такой код:

ArrayEdit[0] := TEdit.Create(self);
with ArrayEdit[0] do Parent := self;

Работает.
Значит причина ошибки та что была уже неоднократно высказана.



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

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

Наверх




Память: 0.57 MB
Время: 0.038 c
4-1093101668
Alexis
2004-08-21 19:21
2004.10.24
Сохранение Bitmap из буфера обмена(Clipboard) в файл


1-1097356874
fmaker
2004-10-10 01:21
2004.10.24
Как сделать форму которая икогда бы не смогла бы быть активной,


3-1095993660
Oleg2
2004-09-24 06:41
2004.10.24
Как сделать, чтобы в гриде редактировать


1-1097482309
Anonim
2004-10-11 12:11
2004.10.24
Экземпляр класса


14-1097115144
TeNY
2004-10-07 06:12
2004.10.24
XPManifest<->XPColorMap?





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
Английский Французский Немецкий Итальянский Португальский Русский Испанский