|
Анатомия деструкции класса
|
|||
---|---|---|---|
#18+
Всем привет! Я ранее использовал в основном управляемые языки, поэтому при знакомстве с Delphi возникло несколько вопросов по основам объектной модели этого языка. Прошу сильно не пинать, если вопросы тупые. 1. Удаление экземпляра класса внутри RTL вызывает у меня недоумение. Вот цитата из system.pas: Код: pascal 1. 2. 3. 4. 5. 6. 7. 8. 9.
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.
И беглая проверка показала, что этот код даже работает. Но чует мое сердце, что работает он только до той поры, пока в промежутке после вызова Button1.Free и до полного выхода из внутренностей TButton, кто-то шустро не займет освободившуюся от Button1 память. 2.2. Я прав, или в Delphi есть какой-то механизм защиты от подобного сценария, и дергать деструктор из обработчика можно не опасаясь? 2.3. Если встроенной защиты нет, то как в среде делфистов принято выходить из таких ситуаций? Желательно без windows-специфичных приемов, типа очереди оконных сообщений. Спасибо. ... |
|||
:
Нравится:
Не нравится:
|
|||
27.10.2021, 22:33 |
|
Анатомия деструкции класса
|
|||
---|---|---|---|
#18+
virtual member, Фига себе ты нафигачил ) Деструктор у объектов, считай один. Это виртуальный метод Destroy. Его переопределяют для каждого класса, где нужна особая логика деструктора В теории можно самому вызывать Destroy. Но так не принято - обычно предпочитают Free, он более безопасный. Ещё более безопасный - FreeAndNil, обязательно загугли Почему Self может быть равен nil. По факту объект это просто указатель на данные. Какие-то объекты инициализируют, вызывая конструкторы. Какие-то помечают как неинициализированные, присваивая им nil. Для обоих случаев прекрасно отработает Free. Где нужно - вызовет деструктор, где не нужно - не сделает ничего ... |
|||
:
Нравится:
Не нравится:
|
|||
27.10.2021, 23:08 |
|
Анатомия деструкции класса
|
|||
---|---|---|---|
#18+
virtual member 1.4. Читал, что в некоторых режимах компиляции работает подсчет ссылок для объектов, но AUTOREFCOUNT ведь директива условной компиляции не моей программы, а модуля system, который уже скомпилирован "на заводе". Что нужно сделать, чтобы в моей программе заработал этот сборщик мусора? Ранее еще и под Linux был, но теперь там выключили. Игрища уже ушедших разработчиков. Надеюсь в будущем везде отключат. ... |
|||
:
Нравится:
Не нравится:
|
|||
27.10.2021, 23:15 |
|
Анатомия деструкции класса
|
|||
---|---|---|---|
#18+
virtual member Если встроенной защиты нет, то как в среде делфистов принято выходить из таких ситуаций? Желательно без windows-специфичных приемов, типа очереди оконных сообщений. Если ты собираешься хранить ссылку на класс после его деструкции принято обнулять ссылку. Но это на совести разработчика. ... |
|||
:
Нравится:
Не нравится:
|
|||
27.10.2021, 23:17 |
|
Анатомия деструкции класса
|
|||
---|---|---|---|
#18+
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.
virtual member 1.3. Если Self таки бывает равна nil, то, простите, чему или кому принадлежит код, который в этот момент выполняется? Принадлежность кода определяется классом, не объектом. Для понимания: Self это псевдопараметр, который передаётся методу и содержит ссылку на объект для которого этот метод вызывается (для методов класса ссылка соответственно на класс, не объект). virtual member 1.4. Читал, что в некоторых режимах компиляции работает подсчет ссылок для объектов... Эта информация уже не актуальна. virtual member 2.2. Я прав, или в Delphi есть какой-то механизм защиты от подобного сценария, и дергать деструктор из обработчика можно не опасаясь? Подобной защиты нет. И делать так не стоит. Есть решения закрывающие наиболее частые сценарии. Например, метод Release в классе TForm. ... |
|||
:
Нравится:
Не нравится:
|
|||
27.10.2021, 23:22 |
|
Анатомия деструкции класса
|
|||
---|---|---|---|
#18+
Kazantsev Alexey virtual member 1.4. Читал, что в некоторых режимах компиляции работает подсчет ссылок для объектов... Эта информация уже не актуальна. ... |
|||
:
Нравится:
Не нравится:
|
|||
27.10.2021, 23:27 |
|
Анатомия деструкции класса
|
|||
---|---|---|---|
#18+
rgreat Я чего-то пропустил?! В 10.4 уже всё вернули взад Код: pascal 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12.
Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21.
... |
|||
:
Нравится:
Не нравится:
|
|||
27.10.2021, 23:30 |
|
Анатомия деструкции класса
|
|||
---|---|---|---|
#18+
virtual member Я ранее использовал в основном управляемые языки И потом говорят, что образование в области программирования никому не нужно. virtual member 1.1. Правильно ли я понимаю, что метод Free, не смотря на обыденную декларацию, является не простым, а "магическим" Неправильно. virtual member И написать свой такой же метод с другим именем не получится? Без проблем. virtual member Зачем проверка Self на nil? Это удобно. Без этого потребовалось бы писать: Код: pascal 1. 2. 3. 4. 5.
Метод Free придумали ровно для того, чтобы не плодить такого убожества. virtual member Разве Self - это не "магическая" константа/переменная, которая всегда указывает на текущий экземпляр? Вы вводите несуществующее волшебное понятие "текущий экземпляр", и оно вводит Вас в заблуждение. Self - это скрытый параметр подпрограммы, являющейся методом класса. Рассмотрите две условных подпрограммы: Код: pascal 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11.
и поймите, что вторая - это просто синтаксический сахар, более удобная запись первой. В процессе развития языков программирования, когда стало много подпрограмм первого типа - для них придумали синтаксис, позволяющий записать их так, как записана вторая. 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 вызывается последним в обработчике события. ... |
|||
:
Нравится:
Не нравится:
|
|||
27.10.2021, 23:55 |
|
Анатомия деструкции класса
|
|||
---|---|---|---|
#18+
Насчет Self понятно. Неявный параметр, который передается во все методы, и, строго говоря, может быть равен чему угодно. По поводу метода Free. Если это самый обычный метод, то выходит, что стек вызовов таких методов может содержать вызов деструктора на любой глубине? Главное, чтобы в этой цепи не было виртуальных/динамических методов, и чтобы после Destroy никто уже не обращался ни к каким данным объекта? То есть, получается, что метод Freе, как и любой другой не виртуальный метод, существует в единственном экземпляре где-то в сегменте кода, и можно быть уверенным, что он будет там всегда, даже если в данный момент не существует ни одного экземпляра того класса, в котором он был декларирован? Прикольно, проверил только что. Путем манипуляций с EBX можно вызывать методы уничтоженного объекта так, чтобы они выполняли работу одноименных методов другого существующего объекта того же типа. Теперь стало понятнее, виртуальные машины управляемых языков работают совсем не так. Там вообще никаких гарантий, что исполняемый код не созданного или уничтоженного объекта существует в данный момент времени хоть где-то. Умерла, так умерла, как говорится. ... |
|||
:
Нравится:
Не нравится:
|
|||
28.10.2021, 01:28 |
|
Анатомия деструкции класса
|
|||
---|---|---|---|
#18+
softwarer И потом говорят, что образование в области программирования никому не нужно. И с чего вы решили, что у меня его нет? Если кто-то не знает тонкостей рантайма Delphi, то это еще значит, что у него нет диплома по дискретной математике. Коммерческий софт я еще на шестой трубе и асме писал, это только ООП у меня "управляемое". ... |
|||
:
Нравится:
Не нравится:
|
|||
28.10.2021, 01:43 |
|
Анатомия деструкции класса
|
|||
---|---|---|---|
#18+
virtual member По поводу метода Free. Если это самый обычный метод, то выходит, что стек вызовов таких методов может содержать вызов деструктора на любой глубине? Главное, чтобы в этой цепи не было виртуальных/динамических методов, и чтобы после Destroy никто уже не обращался ни к каким данным объекта? В цепочке вызовов могут быть и виртуальные и динамические, главное, чтобы после отработки деструктора небыло вызовов таких методов и обращений к полям объекта. virtual member То есть, получается, что метод Freе, как и любой другой не виртуальный метод, существует в единственном экземпляре где-то в сегменте кода, и можно быть уверенным, что он будет там всегда, даже если в данный момент не существует ни одного экземпляра того класса, в котором он был декларирован? Да. В сегменте кода всегда есть все используемые методы. Можно получать адреса методов без создания объектов. ... |
|||
:
Нравится:
Не нравится:
|
|||
28.10.2021, 02:05 |
|
Анатомия деструкции класса
|
|||
---|---|---|---|
#18+
virtual member 2. Типичная ситуация, когда экземпляр класса генерирует событие, запускается обработчик, который в цепочке вызовов на определенном этапе уничтожает тот экземпляр. С управляемыми языками все элементарно, а вот тут я в сплошных непонятках. 2.1. С одной стороны, вижу в интернетах кучу подобного кода (утрировано): Код: pascal 1. 2. 3. 4.
И беглая проверка показала, что этот код даже работает. Но чует мое сердце, что работает он только до той поры, пока в промежутке после вызова Button1.Free и до полного выхода из внутренностей TButton, кто-то шустро не займет освободившуюся от Button1 память. В интернетах ещё со времен царя Гороха много раз написано. Под страхом отрубания рук не следует уничтожать экземпляр класса из его собственного обработчика прямым вызовом методов разрушения! Если вы до сих пор встречаете в интернете примеры такого кода, так это только потому, что интернет это всемирная помойка. Куда все кому приспичило вываливают своё говно. А чистить эту помойку некому. ... |
|||
:
Нравится:
Не нравится:
|
|||
28.10.2021, 02:06 |
|
Анатомия деструкции класса
|
|||
---|---|---|---|
#18+
virtual member То есть, получается, что метод Freе, как и любой другой не виртуальный метод, существует в единственном экземпляре где-то в сегменте кода, и можно быть уверенным, что он будет там всегда, даже если в данный момент не существует ни одного экземпляра того класса, в котором он был декларирован? Метод существует в сегменте кода тогда, когда содержащий его исполняемый файл (exe или dll) загружен в память. Соответственно, пока Вы не поддались нелепой привычке вызывать FreeLibrary ранее выхода из приложения - можете быть уверены, что любой метод, адрес которого Вам удалось получить - продолжает существовать по этому адресу. virtual member softwarer И потом говорят, что образование в области программирования никому не нужно. И с чего вы решили, что у меня его нет? Айтишное образование даёт определённое понимание того, как те или иные вещи устроены под капотом. Соответственно, исчезает потребность задавать вопросы начального уровня. ... |
|||
:
Нравится:
Не нравится:
|
|||
28.10.2021, 03:29 |
|
Анатомия деструкции класса
|
|||
---|---|---|---|
#18+
Kazantsev Alexey В 10.4 уже всё вернули взад Теперь что-ли существует полноценная кроссплатформенность, или все еще какие исключения в компиляторе для мобилок остались? ... |
|||
:
Нравится:
Не нравится:
|
|||
28.10.2021, 10:13 |
|
Анатомия деструкции класса
|
|||
---|---|---|---|
#18+
rgreat Теперь что-ли существует полноценная кроссплатформенность, или все еще какие исключения в компиляторе для мобилок остались? Типа того. Даже зиробейзед строки отключили :) (хелперы по-прежнему зиробейзед) ... |
|||
:
Нравится:
Не нравится:
|
|||
28.10.2021, 10:32 |
|
Анатомия деструкции класса
|
|||
---|---|---|---|
#18+
rgreat И когда же они дозреют... Сомневаюсь, что хелперы переделают. Куча кода молча сломается. ... |
|||
:
Нравится:
Не нравится:
|
|||
28.10.2021, 10:41 |
|
Анатомия деструкции класса
|
|||
---|---|---|---|
#18+
Kazantsev Alexey, Надо... надо. А код можно и поправить 1 раз. ... |
|||
:
Нравится:
Не нравится:
|
|||
28.10.2021, 10:46 |
|
Анатомия деструкции класса
|
|||
---|---|---|---|
#18+
rgreat А код можно и поправить 1 раз. Выискивать весь код где используются хелперы... Такое себе удовольствие. Нет, думется, что теперь это с нами навсегда. Прикол в том, что даже суровые ФПЦшники гневно отвергающие, например, инлайн-переменные, и те состряпали хелпер зиробейзед . А кто-то ещё говорил, что совместимость с дельфями для них не приоритет ... |
|||
:
Нравится:
Не нравится:
|
|||
28.10.2021, 11:09 |
|
Анатомия деструкции класса
|
|||
---|---|---|---|
#18+
Kazantsev Alexey, Дык это решаемый вопрос. Подменить системный хелпер и все само вылезет ошибками. ... |
|||
:
Нравится:
Не нравится:
|
|||
28.10.2021, 11:13 |
|
Анатомия деструкции класса
|
|||
---|---|---|---|
#18+
Kazantsev Alexey суровые ФПЦшники гневно отвергающие, например, инлайн-переменные, и те состряпали хелпер зиробейзед . А кто-то ещё говорил, что совместимость с дельфями для них не приоритет ... |
|||
:
Нравится:
Не нравится:
|
|||
28.10.2021, 11:16 |
|
Анатомия деструкции класса
|
|||
---|---|---|---|
#18+
rgreat Подменить системный хелпер и все само вылезет ошибками. Да я понимаю, что сделать можно, просто работы очень дофига, и нет гарантий, что в процессе не будут внесены ошибки. ... |
|||
:
Нравится:
Не нравится:
|
|||
28.10.2021, 11:17 |
|
Анатомия деструкции класса
|
|||
---|---|---|---|
#18+
rgreat Ну а что делать, если в ембе брали на работу людей с дурными идеями. Фарш назад, как известно, не прокрутить. Нужна ли им ещё одна волна говна, коие и без того накатывают после каждого релиза... хз. ... |
|||
:
Нравится:
Не нравится:
|
|||
28.10.2021, 11:25 |
|
|
start [/forum/topic.php?fid=58&msg=40107656&tid=2036924]: |
0ms |
get settings: |
9ms |
get forum list: |
15ms |
check forum access: |
4ms |
check topic access: |
4ms |
track hit: |
36ms |
get topic data: |
10ms |
get forum data: |
2ms |
get page messages: |
61ms |
get tp. blocked users: |
2ms |
others: | 12ms |
total: | 155ms |
0 / 0 |