
![]() |
Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
|
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[216.73.216.3] |
![]() |
|
Страницы: (245) « Первая ... 243 244 [245] ( Перейти к последнему сообщению ) |
![]() |
Сообщ.
#3661
,
|
|
При этом он ничего не знает про объектные ссылки на самого себя, т.к. сам себе реализует подсчет, а компилятор вызывает _AddRef/_Release только для интерфейсных ссылок. И про это и про привязку механизма подсчета ссылок к интерфейсам. Т.е. если я захочу использовать подсчет ссылок для объектов своего класса, мне придется 1) реализовать IInterface и либо изменить все места в коде, где ранее использовался класс (а это может быть невозможно, привет Sender: TObject), либо реализовать _AddRef/_Release таким образом, чтобы они не удаляли объект. В итоге я оказываюсь перед выбором: наткнуться на грабли, которые могут возникнуть черти где или забить на ARC. Добавлено И нет, не также. Я же говорю: в плюсах я не наследую от shared_ptr и даже не реализую его методы и уж точно мне не придется их реализовывать пустыми, чтобы он не удалил какие-то другие ссылки, я просто не буду его использовать. При этом у меня остаются и используются и классы, и интерфейсы. Захотел подсчет ссылок --- добавил shared_ptr где надо, не захотел --- не добавил. При этом иерархия моих классов/интерфейсов остается нетронутой. |
![]() |
Сообщ.
#3662
,
|
|
Цитата korvin @ О, господи. Я тебе сочувствую. Сталкивался.Отчасти так и есть. Legacy-софт, legacy-DBFки, тоже еще одно порождение воспаленного мозга. Цитата Shaggy @ Это является признаком моего к ней отношения. Это короче, чем сыпать прилагательными. И вежливее заодно. В этом и цель. Заметь, к Борланд у меня всегда были тёплые чувства и таковыми они и остались.намеренное коверканье названия компании-производителя, вероятно, является признаком деловитости как и цель этого действа Вот мы и пришли к консенсусу. Не конкретно мы с тобой, а все мы с конкретно Дельфями. Вот так вот многословно ты рассказал всё то, что до тебя рассказывали мы, разные, покороче и в разных постах. Значит мы всё правильно поняли. Вопрос "а нафик такая фича нужна, если её долго понимать, в ней легко запутаться, она конфликтует с другими предоставляемыми родными же механизмами Дельфей, если это всё легко делается гораздо проще, удобнее, безопаснее и с тем же профитом" остался без ответа, отличного от "у нас таков устав". |
![]() |
Сообщ.
#3663
,
|
|
Цитата korvin @ И про это и про привязку механизма подсчета ссылок к интерфейсам. Т.е. если я захочу использовать подсчет ссылок для объектов своего класса, мне придется 1) реализовать IInterface и либо изменить все места в коде, где ранее использовался класс (а это может быть невозможно, привет Sender: TObject), либо реализовать _AddRef/_Release таким образом, чтобы они не удаляли объект. Не, в дельфе вполне можно реализовать подсчет ссылок внешним по отношению в объекту способом. Будет не так удобно, как shared_ptr (в первую очередь из-за невозможности переопределить оператор вызова метода), но жить можно. Использовать примерно так: ![]() ![]() var MyObj: TSharedPtr<TMyObject>; begin MyObject := TSharedPtr.Create(TMyObject.Create(Args)); Call(MyObj.Value) ; // Value - свойство для получения сырого объекта MyObj.Value.MyMethod(); end; // счетчик ссылок обнуляется, объект уничтожается |
![]() |
Сообщ.
#3664
,
|
|
Цитата korvin @ ++? Еще раз: и? Как COM-интерфейсы связаны с ЯП-интерфейсами, которые существовали еще до COM, и в том же C++ ими назывались классы, имеющие только абстрактные методы (т.к. отдельное ключевое слово вводить не стали)? ну вот microsoft не постеснялась "подменить понятия"(они конечно не язык изменили, а библиотеку написали, но всё-таки..), и? и как можно подменить то, чего не существует? как ты правильно заметил в С++ интерфейсов нет, по крайней мере в языке это не зафиксировано что-то используют в качестве интерфейсов и всё. а ещё это что-то используют в качестве namespace/modules, нас должно смущать наличие у нас unit'ов? или скорее наоборот С++ники должны смущаться от подмены понятий? и почему они обязательно должны быть с чем-то связаны? просто выбран показавшийся удачным механизм я не по этому примеру, а вообще(он просто в качестве иллюстрации) на момент использования ссылки переменная может уже не существовать, в отличие от объекта |
![]() |
Сообщ.
#3665
,
|
|
Короче, korvin, я поясняю. Подсчёт ссылок введён для интерфейсов и только для них. Это всего лишь средство автоматизировать COM-овские необъектные IUnknown::AddRef()/IUnknown::Release(). Необъектные потому, что COM - это объектная технология для любых, включая необъектные, ЯП, реализованная в ОС и ею же предоставляемая посредством API. Это "всего лишь средство автоматизации" не предназначалось больше ни для чего и не должно использоваться больше ни для чего. Ежели у тебя иная архитектурная конструкция классов, особенно если смешанная на интерфейсах/делегатах, будь добр сам её и пиши. Прикол же в том, что никогда не работать с объектами вообще OR никогда не юзать интерфейсы - а только так можно дружить с ними обоими, т.е. попеременно - на практике получается нечасто. Вопрос "на кой хрен было вводить такую фичу, которая решает половину проблем и параллельно создаёт столько же новых на стыке технологий" можно повторять и повторять многократно. Если б в Плюсы вносили всё, что в своё время предлагалось, он бы и 98-го года не пережил.
|
Сообщ.
#3666
,
|
|
|
Shaggy, в C++ есть множественное наследование, поэтому чистые интерфейсы, как сущность языка, не требуются. Они ничем не отличались бы от абстрактных классов. Но я так и не понял, при чем тут подсчет ссылок? Зачем его пихать в интерфейсы, да ещё и криво?
|
![]() |
Сообщ.
#3667
,
|
|
Цитата D_KEY @ Не совсем. Интерфейсы аналогичны частному виду абстрактных классов (только чистые методы + только без атрибутов класса) и частному же варианту их использования (только виртуальное наследование "интерфейсов"). Короче если, возможности абстрактных классов включают возможности интерфейсов, но первые шире вторых. Потому интерфейсов как отдельных сущностей не требуется. При этом справедливости ради следует заметить, что абстрактные классы тоже надо уметь правильно готовить, чтобы получить интерфейсы, иначе неподготовленный программер получит на выходе такую же кашу, как получил korvin с TInterfacedObject. Они ничем не отличались бы от абстрактных классов. Добавлено jack128, получается .Value. -- это аналог ->, да? А счётчики по каким правилам будут меняться? В смысле, что их меняет? |
![]() |
Сообщ.
#3668
,
|
|
Цитата jack128 @ Не, в дельфе вполне можно реализовать подсчет ссылок внешним по отношению в объекту способом. Будет не так удобно, как shared_ptr (в первую очередь из-за невозможности переопределить оператор вызова метода), но жить можно. Это, понятное дело что можно. Другое дело, что нельзя отвязаться от существующего. Цитата Shaggy @ ну вот microsoft не постеснялась "подменить понятия" А они редко этого стесняются. Это показатель? Впрочем у MS так весьма существенная доля рынка, "можно" выпендриваться. У Эмбаркадеро ничтожная доля рынка, им нужно ее завоевывать. Цитата Shaggy @ как ты правильно заметил в С++ интерфейсов нет, по крайней мере в языке это не зафиксировано А C++ нынче единственный язык? Да и на момент создания COM уже был Objective-C и NextStep с его PDO, с которого этот самый COM частично слизали. И, угадай, как реализованы интерфейс и подсчет ссылок в Objective-C? Цитата Shaggy @ а ещё это что-то используют в качестве namespace/modules, нас должно смущать наличие у нас unit'ов? Как бы модули (и интерфейсы модулей) есть много где, тут у делфи никакой уникальности. Цитата Shaggy @ я не по этому примеру, а вообще(он просто в качестве иллюстрации) на момент использования ссылки переменная может уже не существовать, в отличие от объекта И к чему это? Ссылка (грубо) ссылается на некоторое место в памяти (объект), какое ей дело до переменной? Ей важно, чтобы это место было доступно (объект существовал). В чем проблема-то? Цитата Qraizer @ Короче, korvin, я поясняю. Не, я понял как оно работает и почему. Мне непонятно собственно зачем оно так сделано и как с этим нормально жить. Скажем, почему нельзя было IInterface оставить совсем пустым, а для COM сделать что-то отдельное, ну там директиву какую-нибудь, их и так полно в Делфи, одной меньше, одной больше или хотя бы тот самый пресловутый IUnknown, который предоставляет нужные методы? Один хрен в компиляторе специальная магия для интерфейсов, думаю ограничить ее сверху конкретным интерфейсом было бы не сложно. Но видимо ты прав, похоже этот вопрос Цитата Qraizer @ . можно повторять и повторять многократно |
![]() |
Сообщ.
#3669
,
|
|
Цитата Qraizer @ jack128, получается .Value. -- это аналог ->, да? да. Цитата Qraizer @ А счётчики по каким правилам будут меняться? В смысле, что их меняет? там внутри сидит интерфейс. Его реализация и считает ссылки. |
![]() |
Сообщ.
#3670
,
|
|
Т.е. передача параметром. А присваивание? Или метод есть для этого?
D_KEY, как думаешь, в ссылочной семантике ещё что-нибудь нужно? Вот к примеру в массив если такие положить. |
Сообщ.
#3671
,
|
|
|
Васик. Но сами сервера COM первоначально написаны преимущественно на C.
|
![]() |
Сообщ.
#3672
,
|
|
Блин. Есть в дельфе такой тип TValue. Что то типа boost::any, тип позволяющий хранить в себе значения любого типа.
Так вот, для того что сохранить строчку (в дельфе это указатель, 4 байта) этот тип выделяет 2 блока дин памяти, один в 28 байт, другой в 12. Вот скажите, это нормально??? |
![]() |
Сообщ.
#3673
,
|
|
Цитата jack128 @ (в дельфе это указатель, 4 байта) Или 8. Абракадабра ж осилила x64? Кроме того, я так понимаю, что строки в делфи все-же посложней (они разве длину не таскают с собой)? Т.е. указатель на структуру. Как минимум TValue должен хранить идентификатор типа, допустим он int32, возможно под указатель просто единообразно выделяется 8 байт независимо от платформы. Т.о. получаем 12 байт на указатель + id типа. Вторые 28 байт возможно сами данные типа string. Именно значения, хранящего размер строки, возможно еще какую-то служебную информацию (ведь под string'ом может скрываться и AnsiString, и WideString вроде) + указатель уже на сам массив байтов строки. Но это лишь гипотеза. |
![]() |
Сообщ.
#3674
,
|
|
Цитата korvin @ Или 8. Абракадабра ж осилила x64? ну да. SizeOf(Pointer). Цитата korvin @ Т.е. указатель на структуру. указатель на структуру указателем быть не перестает. Цитата korvin @ Как минимум TValue должен хранить идентификатор типа, допустим он int32 SizeOf(Pointer) Цитата korvin @ возможно под указатель просто единообразно выделяется 8 байт независимо от платформы. Нет. Цитата korvin @ Т.о. получаем 12 байт на указатель + id типа. нет, нет. Вообще в этом TValue small buffer optimization даже кой какая есть. Но она не работает для managed типов(для строк в частности). Цитата korvin @ Но это лишь гипотеза. абсолютно неверна. ----- Вообще вот что они сделали, и как оно должно было быть сделано: 1) Понятно что для каких то типов нам по любому понадобится дин память. При этом хочется чтобы пользователю при работе с эти TValue не пришлось эту память освобождать ручками. Значит нам нужно поле интерфейсного типа. 2) Хоцца small buffer optimization. Чтоб всякие инты не требовали дин память. Желание похвальное. 3) Должно поддерживаться хранение managed типов (строк, интерфейсов, дин массивов и тд. Все типы, память за которыми компилятор убивает). OK, ребята сделали так (код схематичный и сильно упрощен) : ![]() ![]() TValue = record private FTypeInfo: PTypeInfo; // "id" типа, как ты выразился. FValueData: IValueData; // тут сидят данные, которые только в дин память влазят FSmallBuff: array[0..12] of byte; public ... end; Ну вроде все нормально, как и должно быть. Но реализация - это швах. 1) SBO не работает для managed типов. Варианты, строки, интерфейсы и даже рекорды без managed полей - все в пролете. С чего такое ограничение - непонятно. 2) IValueData наделен лишней функциональностью, которая требует PTypeInfo. В результате хранятся две копии этого поля: первая в самом TValue, вторая в реализации IValueData. Хотя по идее это должен быть тупо кусок дин памяти, который освобождается при обнулении счетчика ссылок. 3) Вообще реализация IValueData. ![]() ![]() type TValueDataImpl = class(TInterfacedObject, IValueData) private FTypeInfo: PTypeInfo; FData: TArray<Byte>; // тут хранятся дин данные. public FData - это дин. массив. Он сидит в дин памяти. TValueDataImpl - тоже в дин памяти. Зачем нужно два выделения памяти?? Наследование от TInterfacedObject: вообще не нужно. Объекты в дельфи держат 2 указателя(один под VMT, второй под монитор, который вообще нафиг никому не сдался). + каждая реализация интерфейса добавляет еще по SizeOf(Pointer) на инстанс объекта. Зачем все это в данном случае ?? Нужно то всего лишь заменить IValueData на самый обычный динамический массив. Который там и так содержит счетчик ссылок, сам освобождается когда надо. вобщем я бы данные так хранил ![]() ![]() TValue2 = record private FTypeInfo: PTypeInfo; // "id" типа, как ты выразился. FHeapData: TArray<byte>; // тут сидят данные, которые только в дин память влазят FSmallBuff: array[0..12] of byte; public ... end; |
![]() |
Сообщ.
#3675
,
|
|
Хотя нет, напрямую прям дин массив нельзя использовать. Нужно просто IValueData не через наследование от TINtefacedObject реализовывать, а напрямую VMT интерфейса задавать, как они в System.Generics.Defaults компараторы реализовывали. Одно выделение дин памяти для любого managed типа необходимо.
|