
![]() |
Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
|
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[216.73.216.30] |
![]() |
|
Страницы: (245) « Первая ... 238 239 [240] 241 242 ... 244 245 ( Перейти к последнему сообщению ) |
![]() |
Сообщ.
#3586
,
|
|
Она компилируется. Добавлено Опечатки мог бы и сам исправить. Однако, я нашел косяк. Теперь все работает, а жаль (для холивара). =) Он был совсем в другом и в примере, который я сюда написал, его нет. |
Сообщ.
#3587
,
|
|
|
Мяут-Настоящий, Qraizer
Не говорите ерунды. 1) Да, в дельфях тип interface изначально заточен под COM-овский IUnknown и соотв-но должен иметь методы _AddRef и _Release, которые автоматически вызываются компилятором. Но как реализовать эти методы - наше личное дело. И в справке об этом однозначно сказано: если нужна совместимость с COM для связей с "внешним миром" - используй в качестве родителя готовый объект TInterfacedObject, если не нужна - сам задавай методы _AddRef и _Release, как хочешь в соотв-ии со своими "внутренними" задачами. В чем проблема-то? В том, что г-н korvin где-то чё-то услышал об TInterfacedObject и поспешил унаследовать от него подсчет ссылок на интерфейсы с автоудалением объекта, хотя в его задаче "Интерфейсы не надо подсчитывать, они никого не волнуют. Они ничего не хранят, они вообще ничто"?! Дык у него и спросите! (Хотя, если бы он разобрался в принципе подсчета ссылок и работал бы только с интерфейсами, а не с объектами, то тоже все было бы ОК). 2) Сами подумайте, как может\должен работать подсчет ссылок и нужно ли в конструкторе объекта задавать RefCount != 0. Вызовы _AddRef и _Release подставляются автоматически компилятором в момент присваивания ссылки и ее выхода за пределы области видимости. "По контракту" эти методы существуют и соотв-но вызываются только для наследников интерфейса IUnknown. Обычные объекты не обязаны иметь этих методов, и соотв-но компилятор не обязан для ссылок на обычные объекты проверять их "причастность" к реализации IUnknown и "самовольно" вызывать какие-либо методы. Соотв-но и во время конструирования объекта не известно, будет ли он использоваться как интерфейс или как обычный объект. Поэтому объекты-наследники TInterfacedObject создаются с RefCount=0, а увеличение счетчика происходит только в момент присваиванияя ссылки созданного объекта интерфейсу. Ничего нелогичного, и тем более ужасного, в этом нет. Нужно просто об этом знать и понимать как это работает. PS: О любви борманов закладывать в базовые типы TObject, IInterface и т.п, фичи на все случаи жизни, тем самым раздувая их, а с другой стороны ограничивая их использование, уже не раз говорилось и тут, и в дельфийских междусобойчиках. Поэтому повторяться на эту тему не стоит |
Сообщ.
#3588
,
|
|
|
leo, проблема в том, что такие интерфейсы - очень странное решение при проектировании языка.
|
![]() |
Сообщ.
#3589
,
|
|
Цитата leo @ В чем проблема-то? В том, что г-н korvin где-то чё-то услышал об TInterfacedObject и поспешил унаследовать от него подсчет ссылок на интерфейсы с автоудалением объекта И никакой проблемы не было, если бы подсчет ссылок был реализован не через одно место. А заставлять программера разбираться с ![]() ![]() function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall; function _AddRef: Integer; stdcall; function _Release: Integer; stdcall; Когда оно нахер не упало --- это да, это по-дельфийски. Прям как с for. Зачем надо было это пихать в базовый интерфейс? Цитата leo @ хотя в его задаче "Интерфейсы не надо подсчитывать, они никого не волнуют. Они ничего не хранят, они вообще ничто"?! Дык у него и спросите! (Хотя, если бы он разобрался в принципе подсчета ссылок и работал бы только с интерфейсами, а не с объектами, то тоже все было бы ОК). Расскажи-ка как "работать только с интерфейсами" и где в моем примере "работа с объектами". |
Сообщ.
#3590
,
|
|
|
Итак мы выяснили, что в Дельфи "специальные" интерфейсы, и "специальный" цикл for, не похожие на другие языки. ОК.
|
![]() |
Сообщ.
#3591
,
|
|
Цитата leo @ где-то чё-то услышал об TInterfacedObject Где-то, че-то: Цитата When defining a class that supports one or more interfaces, it is convenient to use TInterfacedObject as a base class because it implements the methods of IInterface. А вот Цитата if you are using interfaces only internally in your application, then you have a choice that depends upon the nature of your object and how you decide to use it. и делфийский подход: Цитата By implementing these methods yourself, you can provide an alternative means of lifetime management, disabling reference-counting --- наделать делов, и заставить программера убирать за авторами. |
![]() |
Сообщ.
#3592
,
|
|
leo, ты не о том говоришь. В COM иначе было нельзя, т.к. COM затачивалась как OS-wide фича, которая должна предоставлять необходимый объектный функционал всем приложениям, в частности писаным не только на ООП-языках. С её точки зрения приложение работает с COM-объектами только посредством интерфейсов на них, и ежели объект реализует несколько интерфейсов, о чём приложение знать совершенно не обязано, и даже не обязано, какие объекты реализуют те или иные интерфейсы, они все срыты за UUID, то и подсчитывать нужно интерфейсы. Даже COM-фабрика создаёт объекты по интерфейсам на них. В не объектных языках подсчёт не может выполняться в автоматическом режиме, отсюда и все эти сложности с AddRef и Release.
В нормальной реалии, когда мы имеем нормально поддержанную объектную парадигму, интерфейс является всего лишь пультом ДУ к объекту. Сам объект создаётся не ссылкой на его интерфейс, а указанием конкретного объекта. Счиатть интерфейсы нафик не надо, считать надо объекты. Нормальные объектные аналоги AddRef и Release прекрасно со всем разберутся безо всякого вмешательства. И создаваемый объект уже имеет счётчик 1, что однозначно отличает его состояние "только что создан" от "последняя ссылка освобождена". Замечу, в реализации COM-сервера эту ситуацию следует обходить явным образом руками. |
![]() |
Сообщ.
#3593
,
|
|
Цитата Qraizer @ И создаваемый объект уже имеет счётчик 1, что однозначно отличает его состояние "только что создан" от "последняя ссылка освобождена". какой тяжёлый случай... что хранит счётчик?... количество ссылок кто ссылается на создаваемый объект?... никто чему равен счётчик?... 0 ещё вопросы? |
Сообщ.
#3594
,
|
|
|
Цитата Shaggy @ Цитата Qraizer @ И создаваемый объект уже имеет счётчик 1, что однозначно отличает его состояние "только что создан" от "последняя ссылка освобождена". какой тяжёлый случай... что хранит счётчик?... количество ссылок кто ссылается на создаваемый объект?... никто чему равен счётчик?... 0 ещё вопросы? Как это никто не ссылается, если ты обращаешься к нему? 0 возможен только как промежуточное состояние внутри некоторой операции со ссылкой (в процессе создания и возможного удаления удаления объекта). Объект с 0 счётчиком не должен существовать. |
![]() |
Сообщ.
#3595
,
|
|
Цитата Shaggy @ кто ссылается на создаваемый объект?... никто Т.е. создаваемый объект создается никем и в нигде? Кул стори. |
![]() |
Сообщ.
#3596
,
|
|
Цитата D_KEY @ Как это никто не ссылается, если ты обращаешься к нему? где я к нему обращаюсь? вот воплне легальная конструкция TInterfacedObject.Create; где ссылка? |
Сообщ.
#3597
,
|
|
|
Цитата Shaggy @ Цитата D_KEY @ Как это никто не ссылается, если ты обращаешься к нему? где я к нему обращаюсь? вот воплне легальная конструкция TInterfacedObject.Create; где ссылка? В этой строке и ссылка, ты просто её не назвал. Кстати, тут есть утечка? Добавлено ![]() ![]() make_shared<MyType>(); Это тоже легальная конструкция. Тут тоже не должно создаваться счетчиков и должна быть утечка памяти? Нет, спасибо. |
![]() |
Сообщ.
#3598
,
|
|
Цитата D_KEY @ Как это никто не ссылается, если ты обращаешься к нему? 0 возможен только как промежуточное состояние внутри некоторой операции со ссылкой (в процессе создания и возможного удаления удаления объекта). Объект с 0 счётчиком не должен существовать. Знаешь как они докатились до жопы такой? Вот смотри: ![]() ![]() procedure Foo(x: IInterface); ... Foo(TInterfacedObject.Create); Объект создается до вызова процедуры, счетчик = 0, передается в процедуру по интерфейсу, счетчик увеличивается до единицы. Процедура завершается, счетчик уменьшается до нуля, объект уничтожается. Все как бы хорошо. Но, как следствие, с полями (и, видимо, с переменными) это не прокатывает. Кстати, что происходит в C++-ных ARC-объектах в таких случаях (создание in-place и тут же передача в процедуру)? |
![]() |
Сообщ.
#3599
,
|
|
Цитата D_KEY @ Кстати, тут есть утечка? есть Цитата D_KEY @ В этой строке и ссылка, ты просто её не назвал. ручное управление же... конструктор возвращает объектную ссылку(аналог new int, если угодно) их подчсёт не ведётся ![]() ![]() var O:TObject; begin O:=TObject.Create; end; тут даже самого счётчика нет ![]() ![]() var A,B:IInterface; begin A:=TInterfacedObject.Create; // A.RefCount = 1 B:=TInterfacedObject.Create as IInterface; // B.RefCount = 2 end; а вот тут есть и то и другое (аналог shared_ptr) |
![]() |
Сообщ.
#3600
,
|
|
Цитата Shaggy @ кто ссылается на создаваемый объект? Кстати, D_KEY правильно заметил, если объект существует, но на него никто не ссылается --- это утечка, такие объекты пока только GC умеет удалять. Добавлено Цитата Shaggy @ ![]() ![]() var A, B: IInterface; begin A := TInterfacedObject.Create; // A.RefCount = 1 Замечательно, тогда чем это отличается: ![]() ![]() TMainForm = ... FA: IInterface; ... end; procedure TMainForm.FormCreate; begin FA := TInterfacedObject.Create; end; ? |