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

Вниз

Почему нет ошибки?   Найти похожие ветки 

 
мскл   (2008-02-06 12:38) [0]

Разбираюсь с классами. Уровень начинающий. Возник вопрос, есть такой код:

procedure TForm1.Button1Click(Sender: TObject);
var
 b1, b2, b3: TButton;
begin
 b1.Free;
 b1 := TButton.Create(Self);
 b3 := TButton.Create(Self);
 ShowMessage("b1 = 0x" + IntToHex(Integer(b1), 8));
 b2 := b1;
 ShowMessage("b2 = 0x" + IntToHex(Integer(b2), 8));
 ShowMessage("b3 = 0x" + IntToHex(Integer(b3), 8));
end;


Почему в таком случае не возникает ошибки на выделенном месте: я же пытаюсь уничтожить ещё не созданный объект?

И ещё вопрос про такой фокус - не создаем b3, оставшийся код без изменений, получаем "Abstract error":

var
 b1, b2, b3: TButton;
begin
 b1.Free;
 b1 := TButton.Create(Self);
//  b3 := TButton.Create(Self);
 ShowMessage("b1 = 0x" + IntToHex(Integer(b1), 8));
 b2 := b1;
 ShowMessage("b2 = 0x" + IntToHex(Integer(b2), 8));
 ShowMessage("b3 = 0x" + IntToHex(Integer(b3), 8));


Потом убираем из модифициорванного кода уничтожение не созданного b1, исчезает ошибка:
var
 b1, b2, b3: TButton;
begin
//  b1.Free;
 b1 := TButton.Create(Self);
//  b3 := TButton.Create(Self);
 ShowMessage("b1 = 0x" + IntToHex(Integer(b1), 8));
 b2 := b1;
 ShowMessage("b2 = 0x" + IntToHex(Integer(b2), 8));
 ShowMessage("b3 = 0x" + IntToHex(Integer(b3), 8));


Как это называется?


 
Leonid Troyanovsky ©   (2008-02-06 12:45) [1]


> мскл   (06.02.08 12:38)  

> Как это называется?

Огласи цель исследований.

--
Regards, LVT.


 
ANB   (2008-02-06 12:49) [2]

Посмотри код фрее. У приятно удивись, что он ничего не делает, если ссылка на объект ниловая.


 
clickmaker ©   (2008-02-06 12:49) [3]


> Почему в таком случае не возникает ошибки на выделенном
> месте: я же пытаюсь уничтожить ещё не созданный объект?

To destroy an object, however, you should call the Free method (also inherited from TObject), because Free checks for a nil reference before calling Destroy.
(c) Delphi Help


 
oxffff ©   (2008-02-06 12:52) [4]


> Как это называется?

Это называется использование неинициализированных данных,
а проще говоря грязных слотов стека.


 
Ins ©   (2008-02-06 12:53) [5]

Учитывая, что b1 - локальная переменная, ее значение без инициализации содержит мусор из стека. Этот мусор может содержать ноль - тогда все пройдет гладко, так как [2], [3], а может не ноль - тогда можно ожидать чего угодно, на что только фантизии хватит :)


 
Leonid Troyanovsky ©   (2008-02-06 12:54) [6]


> ANB   (06.02.08 12:49) [2]

> clickmaker ©   (06.02.08 12:49) [3]

А никто не обещал nil для локальных переменных.
Т.е., [4].

--
Regards, LVT.


 
clickmaker ©   (2008-02-06 12:55) [7]


> [6] Leonid Troyanovsky ©   (06.02.08 12:54)

ну повезло человеку ) порадуемся


 
Anatoly Podgoretsky ©   (2008-02-06 13:06) [8]

А плакать потом будем.


 
мскл   (2008-02-06 13:14) [9]

Затеял я это случайно, хотел посмотреть "в живую" как создаются, "копируются" ссылки на экземпляры класса.

Спасибо. Кажется я стал понимать. Но все же задам ещё пару вопросов:
Мой пример с уничтожением до создания - не корректен ведь?
b1.Free;
Я знаю что Free объявлен как простая procedure Free; в TObject. Из этого делаю вывод, что вызывать эту процедуру у неинициализированного объекта нелья. Я прав?

И т.е. получается вся ситуация возникает из-за того, что локальная переменная b1 не факт что изначально является nil? Но вот в этом месте все равно не понимаю - ну если она не nil - тогда b1.Free пытается где-то из грязного адреса b1 отыскать Free, получается тогда "Abstract Error". А если nil, то тогда что, что в таком случае происходит с b1.Free?

Ну и конечно ещё раз спасибо. И извинения за бред, если это так.


 
oxffff ©   (2008-02-06 13:21) [10]


> Мой пример с уничтожением до создания - не корректен ведь?


ДА, не корректен.

> Из этого делаю вывод, что вызывать эту процедуру у неинициализированного
> объекта нелья. Я прав?


НЕТ. Виртуальный метод нельзя. Статический метод можно.


>  А если nil, то тогда что, что в таком случае происходит
> с b1.Free?


clickmaker ©   (06.02.08 12:49) [3]


 
Ins ©   (2008-02-06 13:27) [11]

Происходит следующее:
1. В метод неявно передается b1, внутри метода он будет рассматриваться как параметр Self
2. Вызывается статический метод Free, его адрес известен на этапе компиляции, так что сам факт вызова метода даже с невалидным Self не приведет ни к чему катастрофическому.
3. Внутри метода анализируется Self.
3.1. Если он равен nil, то просто выходим из метода.
3.2. Если он не равен nil, то вызывается виртуальный Destroy. Виртуальный - означает, что его адрес не известен на этапе компиляции и вычисляется в рантайм. Для этого нужно обратиться к Self, прочесть из него адрес VMT и найти в VMT нужный метод по известному смещению. Вот тут и начинается самое интересное - мы читаем из непонятной области памяти непонятное число, считаем что это указатель на VMT. Потом еще читаем из адреса, которое содержит это число + смещение. Потом что получилось пытаемся вызвать. Так как эти адреса на самом деле не имеют смысла - произойдет все что угодно - может AV, может - Abstract Error, может - форматирование жесткого диска. Как повезет :)


 
Ins ©   (2008-02-06 13:29) [12]


> Если он не равен nil, то вызывается виртуальный Destroy


Ой, я хотел выделить слово виртуальный.


 
мскл   (2008-02-06 13:36) [13]

Спасибо. Т.е. получается, что при объявлении объекта в var ему все же выделяется какая-то память (автоматически) для выполнения всех его статических методов без инициализации по конструктору?


 
Ins ©   (2008-02-06 13:40) [14]


> Спасибо. Т.е. получается, что при объявлении объекта в var
> ему все же выделяется какая-то память (автоматически) для
> выполнения всех его статических методов без инициализации
> по конструктору?

Чего? При объявлении объекта в var ему выделяется 4 байта в стеке для ссылки на экземпляр. b1 - это всего лишь указатель на объект в динамической памяти.


 
Ins ©   (2008-02-06 13:41) [15]

Вы что, думаете что адреса методов хранятся внутри экземпляра?


 
oxffff ©   (2008-02-06 13:42) [16]


> мскл   (06.02.08 13:36) [13]
> Спасибо. Т.е. получается, что при объявлении объекта в var
> ему все же выделяется какая-то память (автоматически) для
> выполнения всех его статических методов без инициализации
> по конструктору?


Выделяется слот стека для указателя на объект.
И поскольку экземпляр классового типа не является managed (не в понятии & и o .NET естественно), то для типа не вызывается инициализатор.


 
мскл   (2008-02-06 13:45) [17]


> Чего? При объявлении объекта в var ему выделяется 4 байта
> в стеке для ссылки на экземпляр.


А откуда тогда вызываются статические методы? Ведь память под объект не выделена (= nil).

Как тогда происходт вызов Obj.Free - точнее КУДА он происходит? Obj = nil


 
oxffff ©   (2008-02-06 13:50) [18]


> мскл   (06.02.08 13:45) [17]


compile time binding.


 
Ins ©   (2008-02-06 13:51) [19]


> А откуда тогда вызываются статические методы?

Код метод TObject.Free содержится в единственном экземпляре и его адрес компилятору известен. Соответственно вызов этого метода выглядит так:
mov eax, b1 // Передаем в параметры Self
call TObject.Free

Все. В этих двух строчках кода исключение не возникнет. А вот внутри TObject.Free - возможно, так как Self невалиден.


 
Ins ©   (2008-02-06 13:52) [20]


> oxffff ©   (06.02.08 13:50) [18]

Сорри за offtop, oxffff, если работа все еще нужна, свяжись со мной по ICQ: 371-759-799


 
oxffff ©   (2008-02-06 13:56) [21]


> Ins ©   (06.02.08 13:52) [20]


offtop,

Спасибо.
Можно как-то не через ICQ.
А то для меня увы это темный лес. :)

Напиши на oxffff@yandex.ru свой телефон или контакт и я тебе перезвоню.
Заодно и познакомимся.


 
Ins ©   (2008-02-06 14:10) [22]


> call TObject.Free

Но таким образом вызываются статические методы. Т.е. для определения его адреса self не нужен, адрес известен на этапе компиляции. С виртуальными же методами ситуация совсем другая. Чтобы узнать его адрес, в рантайм идет обращение к Self.



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

Текущий архив: 2008.03.02;
Скачать: CL | DM;

Наверх




Память: 0.53 MB
Время: 0.024 c
15-1201437254
Семеныч
2008-01-27 15:34
2008.03.02
Парадокс


15-1201622881
Andrewtitoff
2008-01-29 19:08
2008.03.02
В чем ошибка?2


3-1192108400
Gurd
2007-10-11 17:13
2008.03.02
memo in database paradox


2-1202312230
Александр В.
2008-02-06 18:37
2008.03.02
TFileStream


2-1202395681
andreoman
2008-02-07 17:48
2008.03.02
как найти узел впри помощи SimpleXML