Гость
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Анатомия деструкции класса / 25 сообщений из 31, страница 1 из 2
27.10.2021, 22:33
    #40107592
virtual member
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Анатомия деструкции класса
Всем привет!

Я ранее использовал в основном управляемые языки, поэтому при знакомстве с Delphi возникло несколько вопросов по основам объектной модели этого языка. Прошу сильно не пинать, если вопросы тупые.

1. Удаление экземпляра класса внутри RTL вызывает у меня недоумение. Вот цитата из system.pas:
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
procedure TObject.Free;
begin
// under ARC, this method isn't actually called since the compiler translates
// the call to be a mere nil assignment to the instance variable, which then calls _InstClear
{$IFNDEF AUTOREFCOUNT}
  if Self <> nil then
    Destroy;
{$ENDIF}
end;


1.1. Правильно ли я понимаю, что метод Free, не смотря на обыденную декларацию, является не простым, а "магическим" методом, за которым стоит несколько больше, чем можно увидеть в его исходнике? И написать свой такой же метод с другим именем не получится?
1.2. Зачем проверка Self на nil? Разве Self - это не "магическая" константа/переменная, которая всегда указывает на текущий экземпляр? Как она может быть nil?
1.3. Если Self таки бывает равна nil, то, простите, чему или кому принадлежит код, который в этот момент выполняется?
1.4. Читал, что в некоторых режимах компиляции работает подсчет ссылок для объектов, но AUTOREFCOUNT ведь директива условной компиляции не моей программы, а модуля system, который уже скомпилирован "на заводе". Что нужно сделать, чтобы в моей программе заработал этот сборщик мусора?

2. Типичная ситуация, когда экземпляр класса генерирует событие, запускается обработчик, который в цепочке вызовов на определенном этапе уничтожает тот экземпляр. С управляемыми языками все элементарно, а вот тут я в сплошных непонятках.
2.1. С одной стороны, вижу в интернетах кучу подобного кода (утрировано):
Код: pascal
1.
2.
3.
4.
procedure Button1Click(Sender: TObject);
begin
  Button1.Free; // или даже Sender.Free
end;


И беглая проверка показала, что этот код даже работает. Но чует мое сердце, что работает он только до той поры, пока в промежутке после вызова Button1.Free и до полного выхода из внутренностей TButton, кто-то шустро не займет освободившуюся от Button1 память.
2.2. Я прав, или в Delphi есть какой-то механизм защиты от подобного сценария, и дергать деструктор из обработчика можно не опасаясь?
2.3. Если встроенной защиты нет, то как в среде делфистов принято выходить из таких ситуаций? Желательно без windows-специфичных приемов, типа очереди оконных сообщений.

Спасибо.
...
Рейтинг: 0 / 0
27.10.2021, 23:08
    #40107599
SOFT FOR YOU
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Анатомия деструкции класса
virtual member,

Фига себе ты нафигачил )

Деструктор у объектов, считай один. Это виртуальный метод Destroy. Его переопределяют для каждого класса, где нужна особая логика деструктора

В теории можно самому вызывать Destroy. Но так не принято - обычно предпочитают Free, он более безопасный. Ещё более безопасный - FreeAndNil, обязательно загугли

Почему Self может быть равен nil. По факту объект это просто указатель на данные. Какие-то объекты инициализируют, вызывая конструкторы. Какие-то помечают как неинициализированные, присваивая им nil. Для обоих случаев прекрасно отработает Free. Где нужно - вызовет деструктор, где не нужно - не сделает ничего
...
Рейтинг: 0 / 0
27.10.2021, 23:15
    #40107601
rgreat
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Анатомия деструкции класса
virtual member
1.4. Читал, что в некоторых режимах компиляции работает подсчет ссылок для объектов, но AUTOREFCOUNT ведь директива условной компиляции не моей программы, а модуля system, который уже скомпилирован "на заводе". Что нужно сделать, чтобы в моей программе заработал этот сборщик мусора?
ARC включен при компиляции под Android и iOS.
Ранее еще и под Linux был, но теперь там выключили.

Игрища уже ушедших разработчиков. Надеюсь в будущем везде отключат.
...
Рейтинг: 0 / 0
27.10.2021, 23:17
    #40107603
rgreat
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Анатомия деструкции класса
virtual member
Если встроенной защиты нет, то как в среде делфистов принято выходить из таких ситуаций? Желательно без windows-специфичных приемов, типа очереди оконных сообщений.

Если ты собираешься хранить ссылку на класс после его деструкции принято обнулять ссылку.

Но это на совести разработчика.
...
Рейтинг: 0 / 0
27.10.2021, 23:22
    #40107604
Kazantsev Alexey
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Анатомия деструкции класса
virtual member
1.1. Правильно ли я понимаю, что метод Free, не смотря на обыденную декларацию, является не простым, а "магическим" методом, за которым стоит несколько больше, чем можно увидеть в его исходнике? И написать свой такой же метод с другим именем не получится?

Метод самый обычный. Написать свой, аналогичный - нет проблем. Приписка касательно ARC устарела.

virtual member
1.2. Зачем проверка Self на nil? Разве Self - это не "магическая" константа/переменная, которая всегда указывает на текущий экземпляр? Как она может быть nil?

Дело в том, что у дельфей деструктор вызывается даже для недоконструированных объектов. Например:
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
constructor ...
begin
 // поля объектов по дефолту были инициализированы нулевыми значениями
 FObject1 := TObject.Create;
 FObject2 := TObject.Create; // Exception here. Исключение в конструкторе приводит к автоматическому вызову деструктора
 FObject3 := TObject.Create; // это поле остаётся неинициализированным.
end;

destructor ...
begin
 // пишем
 FOject1.Free;
 FObject2.Free;
 FObject3.Free;
 // вместо
 if Assigned(FObject1) then
  FObject1.Destroy;
 if Assigned(FObject2) then
  FObject2.Destroy;
 if Assigned(FObject3) then
  FObject3.Destroy;
end;



virtual member
1.3. Если Self таки бывает равна nil, то, простите, чему или кому принадлежит код, который в этот момент выполняется?

Принадлежность кода определяется классом, не объектом. Для понимания: Self это псевдопараметр, который передаётся методу и содержит ссылку на объект для которого этот метод вызывается (для методов класса ссылка соответственно на класс, не объект).

virtual member
1.4. Читал, что в некоторых режимах компиляции работает подсчет ссылок для объектов...

Эта информация уже не актуальна.

virtual member
2.2. Я прав, или в Delphi есть какой-то механизм защиты от подобного сценария, и дергать деструктор из обработчика можно не опасаясь?

Подобной защиты нет. И делать так не стоит. Есть решения закрывающие наиболее частые сценарии. Например, метод Release в классе TForm.
...
Рейтинг: 0 / 0
27.10.2021, 23:27
    #40107605
rgreat
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Анатомия деструкции класса
Kazantsev Alexey
virtual member
1.4. Читал, что в некоторых режимах компиляции работает подсчет ссылок для объектов...

Эта информация уже не актуальна.
Я чего-то пропустил?!
...
Рейтинг: 0 / 0
27.10.2021, 23:30
    #40107606
Kazantsev Alexey
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Анатомия деструкции класса
rgreat
Я чего-то пропустил?!

В 10.4 уже всё вернули взад
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
unit arc;
interface
{$if CompilerVersion >= 24}
 {$legacyifend on}
{$ifend}
{$if defined(AUTOREFCOUNT)}
 {$message hint 'ARC'}
{$else}
 {$message hint 'HANDS'}
{$ifend}
implementation
end.


Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
========================================
Hints
========================================

arc.pas(9) Hint: H1054 HANDS
 D2006 (Win32)
 D2009 (Win32)
 DXE2  (Win32, Win64, OSX32)
 DXE4  (Win32, Win64, OSX32)
 DXE5  (Win32, Win64, OSX32)
 DXE8  (Win32, Win64, OSX32)
 DX2   (Win32, Win64, OSX32)
 DX3   (Win32, Win64, OSX32, OSX64, Linux64)
 DX4   (Win32, Win64, OSX64, iOSSimulator, iOSDevice64, Android, Android64, Linux64)
 D11   (Win32, Win64, OSX64, OSXARM64, iOSDevice64, Android, Android64, Linux64)

arc.pas(7) Hint: H1054 ARC
 DXE4 (iOSSimulator, iOSDevice)
 DXE5 (iOSSimulator, iOSDevice, Android)
 DXE8 (iOSSimulator, iOSDevice32, iOSDevice64, Android)
 DX2  (iOSSimulator, iOSDevice32, iOSDevice64, Android, Linux64)
 DX3  (iOSSimulator, iOSDevice32, iOSDevice64, Android, Android64)
...
Рейтинг: 0 / 0
27.10.2021, 23:55
    #40107608
softwarer
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Анатомия деструкции класса
virtual member
Я ранее использовал в основном управляемые языки

И потом говорят, что образование в области программирования никому не нужно.

virtual member
1.1. Правильно ли я понимаю, что метод Free, не смотря на обыденную декларацию, является не простым, а "магическим"

Неправильно.

virtual member
И написать свой такой же метод с другим именем не получится?

Без проблем.

virtual member
Зачем проверка Self на nil?

Это удобно. Без этого потребовалось бы писать:

Код: pascal
1.
2.
3.
4.
5.
finally
  if A <> nil then A.Destroy;
  if B <> nil then B.Destroy;
  if C <> nil then C.Destroy;
end;


Метод Free придумали ровно для того, чтобы не плодить такого убожества.

virtual member
Разве Self - это не "магическая" константа/переменная, которая всегда указывает на текущий экземпляр?

Вы вводите несуществующее волшебное понятие "текущий экземпляр", и оно вводит Вас в заблуждение. Self - это скрытый параметр подпрограммы, являющейся методом класса. Рассмотрите две условных подпрограммы:

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
{ Первая }
procedure Foo(ASelf: TBar; ANewValue: integer);
begin
  ASelf.Value := ANewValue;
end;

{ Вторая }
procedure TBar.Foo(ANewValue: integer);
begin
  Value := ANewValue;
end;


и поймите, что вторая - это просто синтаксический сахар, более удобная запись первой. В процессе развития языков программирования, когда стало много подпрограмм первого типа - для них придумали синтаксис, позволяющий записать их так, как записана вторая.

virtual member
Как она может быть nil?

Так же, как может быть равен nil любой другой объектный параметр подпрограммы.

virtual member
1.3. Если Self таки бывает равна nil, то, простите, чему или кому принадлежит код, который в этот момент выполняется?

С чего Вы взяли, что код кому-то принадлежит? Может, этот кто-то ещё может выполняемый код купить, продать или там подарить? Код как Матроскин, свой собственный.

virtual member
2. Типичная ситуация, когда экземпляр класса генерирует событие, запускается обработчик, который в цепочке вызовов на определенном этапе уничтожает тот экземпляр.

Она не типичная, а довольно дурацкая.

virtual member
И беглая проверка показала, что этот код даже работает. Но чует мое сердце, что работает он только до той поры, пока в промежутке после вызова Button1.Free и до полного выхода из внутренностей TButton, кто-то шустро не займет освободившуюся от Button1 память.

Вопрос не в том, займёт или нет. Вопрос в том, что после вызова деструктора не должно происходить обращений к полям и виртуальным методам этого объекта. Фактически после этого вызова Self становится невалидным указателем и не должен использоваться. Но проконтролировать это сложно, и можно быть уверенным, что когда-нибудь здесь начнутся проблемы.

virtual member
2.3. Если встроенной защиты нет, то как в среде делфистов принято выходить из таких ситуаций?

Во времена Delphi 1 придумали метод TForm.Release специально для решения этой проблемы. Минус подхода в том, что он правильно работает только если в коде не употребляется Application.ProcessMessages. Как принято выходить.... ну, в первую очередь - обычно в них просто незачем входить. Опишите ситуацию, где Вы хотите такое делать - и 99.9% окажется, что нужно присвоить компоненту адекватного Owner-а и ничего руками не дёргать.

Тем не менее, если очень хочется - такое можно вполне безопасно делать, если Free вызывается последним в обработчике события.
...
Рейтинг: 0 / 0
28.10.2021, 01:28
    #40107611
virtual member
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Анатомия деструкции класса
Насчет Self понятно. Неявный параметр, который передается во все методы, и, строго говоря, может быть равен чему угодно.

По поводу метода Free. Если это самый обычный метод, то выходит, что стек вызовов таких методов может содержать вызов деструктора на любой глубине? Главное, чтобы в этой цепи не было виртуальных/динамических методов, и чтобы после Destroy никто уже не обращался ни к каким данным объекта?

То есть, получается, что метод Freе, как и любой другой не виртуальный метод, существует в единственном экземпляре где-то в сегменте кода, и можно быть уверенным, что он будет там всегда, даже если в данный момент не существует ни одного экземпляра того класса, в котором он был декларирован?

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

Теперь стало понятнее, виртуальные машины управляемых языков работают совсем не так. Там вообще никаких гарантий, что исполняемый код не созданного или уничтоженного объекта существует в данный момент времени хоть где-то. Умерла, так умерла, как говорится.
...
Рейтинг: 0 / 0
28.10.2021, 01:43
    #40107612
virtual member
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Анатомия деструкции класса
softwarer
И потом говорят, что образование в области программирования никому не нужно.

И с чего вы решили, что у меня его нет? Если кто-то не знает тонкостей рантайма Delphi, то это еще значит, что у него нет диплома по дискретной математике.
Коммерческий софт я еще на шестой трубе и асме писал, это только ООП у меня "управляемое".
...
Рейтинг: 0 / 0
28.10.2021, 02:05
    #40107613
Kazantsev Alexey
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Анатомия деструкции класса
virtual member
По поводу метода Free. Если это самый обычный метод, то выходит, что стек вызовов таких методов может содержать вызов деструктора на любой глубине? Главное, чтобы в этой цепи не было виртуальных/динамических методов, и чтобы после Destroy никто уже не обращался ни к каким данным объекта?

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

virtual member
То есть, получается, что метод Freе, как и любой другой не виртуальный метод, существует в единственном экземпляре где-то в сегменте кода, и можно быть уверенным, что он будет там всегда, даже если в данный момент не существует ни одного экземпляра того класса, в котором он был декларирован?

Да. В сегменте кода всегда есть все используемые методы. Можно получать адреса методов без создания объектов.
...
Рейтинг: 0 / 0
28.10.2021, 02:06
    #40107614
northener
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Анатомия деструкции класса
virtual member

2. Типичная ситуация, когда экземпляр класса генерирует событие, запускается обработчик, который в цепочке вызовов на определенном этапе уничтожает тот экземпляр. С управляемыми языками все элементарно, а вот тут я в сплошных непонятках.
2.1. С одной стороны, вижу в интернетах кучу подобного кода (утрировано):
Код: pascal
1.
2.
3.
4.
procedure Button1Click(Sender: TObject);
begin
  Button1.Free; // или даже Sender.Free
end;


И беглая проверка показала, что этот код даже работает. Но чует мое сердце, что работает он только до той поры, пока в промежутке после вызова Button1.Free и до полного выхода из внутренностей TButton, кто-то шустро не займет освободившуюся от Button1 память.

В интернетах ещё со времен царя Гороха много раз написано. Под страхом отрубания рук не следует уничтожать экземпляр класса из его собственного обработчика прямым вызовом методов разрушения! Если вы до сих пор встречаете в интернете примеры такого кода, так это только потому, что интернет это всемирная помойка. Куда все кому приспичило вываливают своё говно. А чистить эту помойку некому.
...
Рейтинг: 0 / 0
28.10.2021, 03:29
    #40107615
softwarer
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Анатомия деструкции класса
virtual member
То есть, получается, что метод Freе, как и любой другой не виртуальный метод, существует в единственном экземпляре где-то в сегменте кода, и можно быть уверенным, что он будет там всегда, даже если в данный момент не существует ни одного экземпляра того класса, в котором он был декларирован?

Метод существует в сегменте кода тогда, когда содержащий его исполняемый файл (exe или dll) загружен в память. Соответственно, пока Вы не поддались нелепой привычке вызывать FreeLibrary ранее выхода из приложения - можете быть уверены, что любой метод, адрес которого Вам удалось получить - продолжает существовать по этому адресу.

virtual member
softwarer
И потом говорят, что образование в области программирования никому не нужно.

И с чего вы решили, что у меня его нет?

Айтишное образование даёт определённое понимание того, как те или иные вещи устроены под капотом. Соответственно, исчезает потребность задавать вопросы начального уровня.
...
Рейтинг: 0 / 0
28.10.2021, 10:13
    #40107644
rgreat
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Анатомия деструкции класса
Kazantsev Alexey
В 10.4 уже всё вернули взад
Слава яйцам!

Теперь что-ли существует полноценная кроссплатформенность, или все еще какие исключения в компиляторе для мобилок остались?
...
Рейтинг: 0 / 0
28.10.2021, 10:32
    #40107651
Kazantsev Alexey
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Анатомия деструкции класса
rgreat
Теперь что-ли существует полноценная кроссплатформенность, или все еще какие исключения в компиляторе для мобилок остались?

Типа того. Даже зиробейзед строки отключили :) (хелперы по-прежнему зиробейзед)
...
Рейтинг: 0 / 0
28.10.2021, 10:39
    #40107653
rgreat
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Анатомия деструкции класса
Kazantsev Alexey
(хелперы по-прежнему зиробейзед)



И когда же они дозреют...
...
Рейтинг: 0 / 0
28.10.2021, 10:41
    #40107654
Kazantsev Alexey
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Анатомия деструкции класса
rgreat
И когда же они дозреют...

Сомневаюсь, что хелперы переделают. Куча кода молча сломается.
...
Рейтинг: 0 / 0
28.10.2021, 10:46
    #40107656
rgreat
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Анатомия деструкции класса
Kazantsev Alexey,

Надо... надо.

А код можно и поправить 1 раз.
...
Рейтинг: 0 / 0
28.10.2021, 11:09
    #40107661
Kazantsev Alexey
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Анатомия деструкции класса
rgreat
А код можно и поправить 1 раз.

Выискивать весь код где используются хелперы... Такое себе удовольствие. Нет, думется, что теперь это с нами навсегда. Прикол в том, что даже суровые ФПЦшники гневно отвергающие, например, инлайн-переменные, и те состряпали хелпер зиробейзед . А кто-то ещё говорил, что совместимость с дельфями для них не приоритет
...
Рейтинг: 0 / 0
28.10.2021, 11:13
    #40107665
rgreat
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Анатомия деструкции класса
Kazantsev Alexey,

Дык это решаемый вопрос. Подменить системный хелпер и все само вылезет ошибками.
...
Рейтинг: 0 / 0
28.10.2021, 11:16
    #40107666
rgreat
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Анатомия деструкции класса
Kazantsev Alexey
суровые ФПЦшники гневно отвергающие, например, инлайн-переменные, и те состряпали хелпер зиробейзед . А кто-то ещё говорил, что совместимость с дельфями для них не приоритет

...
Рейтинг: 0 / 0
28.10.2021, 11:17
    #40107667
Kazantsev Alexey
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Анатомия деструкции класса
rgreat
Подменить системный хелпер и все само вылезет ошибками.

Да я понимаю, что сделать можно, просто работы очень дофига, и нет гарантий, что в процессе не будут внесены ошибки.
...
Рейтинг: 0 / 0
28.10.2021, 11:19
    #40107669
rgreat
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Анатомия деструкции класса
Kazantsev Alexey,

Ну а что делать, если в ембе брали на работу людей с дурными идеями.
...
Рейтинг: 0 / 0
28.10.2021, 11:25
    #40107672
Kazantsev Alexey
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Анатомия деструкции класса
rgreat
Ну а что делать, если в ембе брали на работу людей с дурными идеями.

Фарш назад, как известно, не прокрутить. Нужна ли им ещё одна волна говна, коие и без того накатывают после каждого релиза... хз.
...
Рейтинг: 0 / 0
28.10.2021, 11:28
    #40107673
rgreat
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Анатомия деструкции класса
Kazantsev Alexey,

Думаю в данном случае изменения будут приняты позитивно.
Кодовая база должна быть едина.

Я бы zero-based хелперами вообще не пользовался, от греха.
...
Рейтинг: 0 / 0
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Анатомия деструкции класса / 25 сообщений из 31, страница 1 из 2
Целевая тема:
Создать новую тему:
Автор:
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]