Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2004.10.24;
Скачать: CL | DM;

Вниз

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

 
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;
Скачать: CL | DM;

Наверх




Память: 0.58 MB
Время: 0.029 c
14-1093435643
Красная Майка
2004-08-25 16:07
2004.10.24
ChGMP - Черноголовская встреча Мастаков! Coming soon...


1-1097169006
F1
2004-10-07 21:10
2004.10.24
Как узнать нажата ли только что созданая кнопка?


1-1097215738
Девушка
2004-10-08 10:08
2004.10.24
Abstact error


3-1096450101
Artem777
2004-09-29 13:28
2004.10.24
Слишком большое колличество курсоров


4-1095593167
ArhDD
2004-09-19 15:26
2004.10.24
Как в WinApi из Edit записать в переменную integer?