Форум: "Начинающим";
Текущий архив: 2008.03.02;
Скачать: [xml.tar.bz2];
ВнизПочему нет ошибки? Найти похожие ветки
← →
мскл (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;
Скачать: [xml.tar.bz2];
Память: 0.5 MB
Время: 0.04 c