Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Начинающим";
Текущий архив: 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
15-1201527834
Kerk
2008-01-28 16:43
2008.03.02
50 работодателей мечты для молодого специалиста


3-1192477342
ari_9
2007-10-15 23:42
2008.03.02
как правильно выполн."по таймеру" действия в бд (клиент-сервер) ?


15-1199481044
Семен Сурков
2008-01-05 00:10
2008.03.02
О выборе платформы для ВЕБ и ФТП сервера II


2-1202469477
saNat
2008-02-08 14:17
2008.03.02
Формирование документа Word по шаблону, защищенному паролем


2-1201985154
Бэтман
2008-02-02 23:45
2008.03.02
edit





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