Delphi vs C++ vs C#
, ну и Java немножко, где-то ближе к старшему байту номеров страниц
![]() |
Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
|
| ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
| [216.73.216.156] |
|
|
Правила раздела:
| Страницы: (495) « Первая ... 165 166 [167] 168 169 ... 494 495 ( Перейти к последнему сообщению ) |
Delphi vs C++ vs C#
, ну и Java немножко, где-то ближе к старшему байту номеров страниц
|
Сообщ.
#2491
,
|
|
|
|
Цитата Qraizer @ Думаю, компилятор вместо передачи указателя на фрейм внешней функции явно обращается ровно на один фрейм выше. Или заюзал оптимизацию "подавления указателей на стековые фреймы". Или ещё чего, мало ли причин можно придумать. Компилятор тут кагбэ и не приделах, т.к. он даже и не в курсе, что переданный нетипизированный указатель - это указатель на локальную процедуру, в ином случае сразу бы получили "Local procedure/function 'UseLocalVar' assigned to procedure variable". Да, тут есть такой нюанс, если в контексте локальной процедуры используются переменные, объявленные в родительской процедуре ![]() ![]() procedure ParentProc; var N: Integer; procedure LocalProc; begin Inc(N); end; begin LocalProc; end; То перед её вызовом в стек добавляется указатель на текущий (родительской процедуры) кадр стека, по которому в дальнейшем, в контексте локальной процедуры, будут вычисляться адреса переменных. ![]() ![]() LocalProc; ![]() ![]() push ebp ;сохраняется указатель на кадр стека call LocalProc pop ecx в контексте локальной процедуры: ![]() ![]() Inc(N); ![]() ![]() mov eax,[ebp+$08] ;по смещению от указателя на кадр стека локальной процедуры вычисляется указатель на кадр стека родительской процедуры inc dword ptr [eax-$04] ;теперь относительно указателя на кадр стека можно получить все адреса переменных Этот же принцип действует и для рекурсивных вызовов самой локальной процедуры. Возможно дело просто в реализации? Во первых: а смысл? А во вторых: локальные процедуры тогда бы на порядок потеряли в скорости выполнения. Цитата MyNameIsIgor @ Я то надеялся, что тут будет, например, DesweR и подхватит знамя "убогой объектной системы" - хоть какая-то движуха. DesweR не читает советских газет Добавлено Цитата korvin @ кстати, что-то вспомнилось АОП. допустим нам нужно, чтобы для объектов какого-то класса (и его потомков) перед или после выполнения какого-то метода происходили какие-то действия (запись в лог или что-то такое). причем классы эти могут быть не наши (т.е. изменить их определение может быть невозможным). как поступить в топиковых языках? дополнительно: если это нужно добавить ко всем объектам (в делфи и C# корень один, а в его нет, потому и вопрос)? Для C# можно сказать решение готово, читал эту статью на хабре, для Delphi надо подумать... |
|
Сообщ.
#2492
,
|
|
|
|
Цитата korvin @ кстати, что-то вспомнилось АОП. допустим нам нужно, чтобы для объектов какого-то класса (и его потомков) перед или после выполнения какого-то метода происходили какие-то действия (запись в лог или что-то такое). причем классы эти могут быть не наши (т.е. изменить их определение может быть невозможным). как поступить в топиковых языках? дополнительно: если это нужно добавить ко всем объектам (в делфи и C# корень один, а в его нет, потому и вопрос)? Для С++ через "добавление" чего-то перед вызовом и после, пожалуй нельзя. Если только активно не используется "шаблонный метод", да или просто нет открытых виртуальных функций - в этом случае, все уже почти готово. В качестве общего решения можно было бы предложить работать через специальный указатель(выполняющий запись в лог до и после любого обращения к объекту) и/или обертку, реализующую интерфейс класса... Добавлено Цитата DesweR @ Во первых: а смысл? А во вторых: локальные процедуры тогда бы на порядок потеряли в скорости выполнения. 1) смысл в том, чтобы локальные функции были удобным инструментом, а не странным, зависимым от реализации механизмом, сомнительной пользы. 2) ну да, пожалуй для языков без сборки мусора с этим все несколько сложнее. Приходится или копировать данные, или вручную отслеживать ссылки. В С++ можно все организовать через shared_ptr'ы, но в этом случае мы используем динамическую память "на ровном месте", практически без необходимости. Кстати, как у вас лямбды захватывают контекст? |
|
Сообщ.
#2493
,
|
|
|
|
Цитата D_KEY @ Кстати, как у вас лямбды захватывают контекст? вроде уже обсуждали, в дельфи - лямбды - это неявные объекты, реализующие интерфейс. читай, тот же самый приплюснутый shared_ptr. А локальные процедуры были введены в паскаль(НЕ object pascal) задолго до того как появились интерфейсы. |
|
Сообщ.
#2494
,
|
|
|
|
Цитата D_KEY @ 1) смысл в том, чтобы локальные функции были удобным инструментом, а не странным, зависимым от реализации механизмом, сомнительной пользы. Так они и так удобный инструмент, ни больше ни меньше А если нужна передача вовне - к услугам анонимные методы. Цитата D_KEY @ Кстати, как у вас лямбды захватывают контекст? Сейчас точно не посмотрю, захватывают переменные по ссылкам, а не по значению. К слову, управление временем жизни захваченного контекста реализовано посредством интерфейсного объекта. |
|
Сообщ.
#2495
,
|
|
|
|
Цитата DesweR @ Цитата D_KEY @ Кстати, как у вас лямбды захватывают контекст? Сейчас точно не посмотрю, захватывают переменные по ссылкам, а не по значению. А если они после захвата уничтожаются в создающем лямбду коде, но продолжают использоваться в том месте, куда была отдана лямбда? Цитата К слову, управление временем жизни захваченного контекста реализовано посредством интерфейсного объекта. Ну да. Подсчет ссылок. |
|
Сообщ.
#2496
,
|
|
|
|
Цитата D_KEY @ А если они после захвата уничтожаются в создающем лямбду коде, но продолжают использоваться в том месте, куда была отдана лямбда? Если ты уничтожаешь объект сам явно - то скорее всего |
|
Сообщ.
#2497
,
|
|
|
|
Цитата DesweR @ Ну так об этом и спрашивал. Уже понял.Компилятор тут кагбэ и не приделах, т.к. он даже и не в курсе, что переданный нетипизированный указатель - это указатель на локальную процедуру, в ином случае сразу бы получили "Local procedure/function 'UseLocalVar' assigned to procedure variable". Просто какая-то нестыковка. Во вашим словам получается, что использовать их всё-таки нельзя, а у народа вон получилось. Плюс к этому, как я смотрю по листингу, проблемы в общем-то нет. Точнее, есть: Цитата DesweR @ но точно такая же, как и у нас. Я уже D_KEY-ю говорил: если контект определения сущности, на которую ссылаемся, жив, то всё работает на ура, если же уже мёртв, то ссылка оказывается висячей в нивочто. И проблема как раз в том, что определить, какая ситуация из этих двух сейчас имеет место быть, в общем случае невозможно. У нас есть полуавтоматические shared_ptr/weak_ptr, но полностью автоматического решения представить не могу, если честно.Возможно дело просто в реализации? Цитата jack128 @ Задолго до того, как появлись процедурные типы. Так точнее. А локальные процедуры были введены в паскаль(НЕ object pascal) задолго до того как появились интерфейсы. |
|
Сообщ.
#2498
,
|
|
|
|
Цитата Qraizer @ если контект определения сущности, на которую ссылаемся, жив, то всё работает на ура, если же уже мёртв, то ссылка оказывается висячей в нивочто. И проблема как раз в том, что определить, какая ситуация из этих двух сейчас имеет место быть, в общем случае невозможно. ИМХО, проблема в языках, которые не могут обеспечить нужное время жизни объекта... Если для С++ на это есть причины, то какие причины у такого языка, как Delphi, который изначально ориентирован на область прикладного программирования? Или это просто наследство? Цитата У нас есть полуавтоматические shared_ptr/weak_ptr, но полностью автоматического решения представить не могу, если честно. Да, думаю что его нет. Кстати, как я понял, интерфейсы в Delphi также обеспечивают подсчет ссылок и могут в данном случае использоваться как наши shared_ptr и weak_ptr. Кстати, есть ли какой-то аналог последнего(weak_ptr) в Delphi? |
|
Сообщ.
#2499
,
|
|
|
|
Цитата Qraizer @ Просто какая-то нестыковка. Во вашим словам получается, что использовать их всё-таки нельзя, а у народа вон получилось. У такого "народа", не сомневаюсь, получится и объекты использовать после их уничтожения. Кто их заставляет вместо процедурных типов использовать нетипизированные указатели или отключать "Typed @ operator"? Цитата Qraizer @ И проблема как раз в том, что определить, какая ситуация из этих двух сейчас имеет место быть, в общем случае невозможно. Если писать в соответствии с руководством по языку, то таких проблем вообще не возникнет. Цитата D_KEY @ Кстати, есть ли какой-то аналог последнего(weak_ptr) в Delphi? Воспроизводится легко. А вообще, это смотря какая задача, грамотный дизайн может и исключить потребность в weak_ptr. |
|
Сообщ.
#2500
,
|
|
|
|
Цитата DesweR @ Этточно. Ни ошибок компиляции, ни отладки. Если писать в соответствии с руководством по языку, то таких проблем вообще не возникнет. |
|
Сообщ.
#2501
,
|
|
|
|
Цитата DesweR @ У такого "народа", не сомневаюсь, получится и объекты использовать после их уничтожения. Кто их заставляет вместо процедурных типов использовать нетипизированные указатели или отключать "Typed @ operator"? Вот, наконец-то вы начинаете понимать и "классическую" нашу аргументацию Цитата Цитата D_KEY @ Кстати, есть ли какой-то аналог последнего(weak_ptr) в Delphi? Воспроизводится легко. А вообще, это смотря какая задача, грамотный дизайн может и исключить потребность в weak_ptr. Можно узнать, как воспроизводится? Относительно дизайна, думаю, что ты не прав. Иногда нужно иметь ссылку на объект, но не являться одним из его "владельцев". Это касается даже языков со сборкой мусора, примеры уже приводились. Правда ситуаций таких немного. |
|
Сообщ.
#2502
,
|
|
|
|
Цитата D_KEY @ Можно узнать, как воспроизводится? А как захочешь ![]() ![]() type ISharedPtr = interface //наш абстрактный SharedPtr procedure SomeProc; //якобы объект которым владеет SharedPtr end; TSharedPtr = class(TInterfacedObject, ISharedPtr) public destructor Destroy; override; function IsAlive: Boolean; //если счетчик ссылок > 0 то True procedure SomeProc; end; TWeakPtr = record strict private FObj: TSharedPtr; function GetObj: TSharedPtr; public procedure Init(const AObj: ISharedPtr); property Obj: TSharedPtr read GetObj; end; destructor TSharedPtr.Destroy; begin Writeln('SharedPtr.Destroy'); end; function TSharedPtr.IsAlive: Boolean; begin Result := (FRefCount > 0); end; procedure TSharedPtr.SomeProc; begin Writeln('SharedPtr.SomeProc'); end; procedure TWeakPtr.Init(const AObj: ISharedPtr); begin //объект не увеличивает счетчик ссылок интерфейса FObj := (AObj as TSharedPtr); end; function TWeakPtr.GetObj: TSharedPtr; begin Result := nil; if FObj.IsAlive then Result := FObj else raise Exception.Create('WeakPtr: SharedPtr is destroyed'); end; var Intf: ISharedPtr; WeakPtr: TWeakPtr; begin try Intf := TSharedPtr.Create; WeakPtr.Init(Intf); Intf.SomeProc; WeakPtr.Obj.SomeProc; Intf := nil; //уничтожаем SharedPtr WeakPtr.Obj.SomeProc; except on E: Exception do Writeln(E.Message); end; ReadLn; end. ![]() ![]() SharedPtr.SomeProc SharedPtr.SomeProc SharedPtr.Destroy WeakPtr: SharedPtr is destroyed |
|
Сообщ.
#2503
,
|
|
|
|
DesweR
если шаредПтр уже уничтожен, то как же ты можешь обращаться к его методу IsAlive ?? D_KEY а как WeakPtr в cpp реализован?? |
|
Сообщ.
#2504
,
|
|
|
|
Цитата jack128 @ D_KEY а как WeakPtr в cpp реализован?? Он тесно связан с shared_ptr, его можно получить только из shared_ptr'а. Сам объект, которым мы владеем удалится, как только на него не будет активных ссылок(shared_ptr), а вот запись, хранящая счетчики не удаляется, пока не останется ссылок на эту запись(т.е. учитывается и weak_ptr). Таким образом на объект хранятся два счетчика - один для подсчета ссылок на объект(и когда он обнуляется происходит удаление объекта), другой для подсчета ссылок на саму запись об этом объекте(когда обнуляется он, происходит удаление этой записи). Думаю, в реализациях есть какие-то оптимизации, но концептуально это происходит так. |
|
Сообщ.
#2505
,
|
|
|
|
D_KEY
а. Ну тогда никаких принципиальных проблем для аналогичной реализации в дельфи - нет. Добавлено ![]() ![]() IRefCounter<T: class> = interface procedure AddShared; procedure ReleaseShared; // когда FSharedCount = 0 - уничтожаем объект и isAlive = false. ВНИМАНИЕ - это НЕ RefCount, который в TInterfacedObject'е сидит, а отдельный счетчик function IsAlive: Integer; fucntion GetValue: T; end; ISharedPtr<T: class> = interface function GetValue: T; property Value: T read GetValue; end; TSharedPtr<T: class> = class(TInterfacedObject, ISharedPtr<T>) private FCounter: IRefCounter; protected function _AddRef: Integer; // FCounter.AddShared function _Release: Integer; // fCounter.ReleaseShared; public constructor Create(AValue: T); // fCounter := TRefCounter<T>.Create(AVAlue); end; IWeakPtr<T: class> = interface function GetValue: T; property Value: T read GetValue; function IsAlive: boolean; end; TWeakPtr<T: class> = class(TInterfacedObject, IWeakPtr<T>) private FCounter: IRefCounter<T>; protected function GetValue: T; // fCounter.GetValue; function IsAlive: boolean; // fCounter.IsAlive; public constructor Create(AValue: ISharedPtr<T>); // fCounter := (AValue as TSharedPtr<T>).FCounter; end; |