Типы данных

Вопросы программирования на Free Pascal, использования компилятора и утилит.

Модератор: Модераторы

Re: Типы данных

Сообщение Лекс Айрин » 14.12.2017 12:40:28

olegy123, нет, конечно, но к этому стремятся.
Аватара пользователя
Лекс Айрин
долгожитель
 
Сообщения: 5723
Зарегистрирован: 19.02.2013 16:54:51
Откуда: Волгоград

Re: Типы данных

Сообщение Cheb » 18.12.2017 14:46:52

Гуглишь TInterfacedObject . Вникаешь.
Делаешь свои классы его потомками, или сам делаешь их = class(TObject, IUnknown)

После этого все классы у тебя становятся менеджед, со счётчиком ссылок, и компилятор сам заботится чтобы экземпляр класса удалился когда на него протухнет последняя ссылка.
Только не забывать везде .Free поменять на := nil; (генерирует неявный вызов _Release)

В паскале встроенное закулисное окучивание переменных подобных типов, при каждом присваивании вставляется проверка счётчика ссылок.
Точно так же, как это делается с массивамми и строками.
Я даже больше скажу: если у вас массив, содержащий такие объекты, то при удалении массива будет выполнен проход вдоль него и удаление объектов.
Аватара пользователя
Cheb
энтузиаст
 
Сообщения: 994
Зарегистрирован: 06.06.2005 15:54:34

Re: Типы данных

Сообщение serbod » 19.12.2017 11:22:25

Cheb писал(а):После этого все классы у тебя становятся менеджед, со счётчиком ссылок, и компилятор сам заботится чтобы экземпляр класса удалился когда на него протухнет последняя ссылка.


Увы, тип class - это тупой указатель, без влияния на счетчик ссылок. Для переменных типа class счетчик ссылок не работает. Нужен тип переменной interface (которой присвоен экземпляр class), а это несколько ограничивает удобство пользования.

Но можно не заморачиваться особо с интерфейсами, а использовать "слабую ссылку" - интерфейс, содержащий только указатель на основной объект. "Слабая ссылка" будет висеть в памяти, пока кто-нибудь на нее ссылается. При освобождении основного объекта в "слабой ссылке" указатель меняется на nil, и все, кто имеет "слабую ссылку" могут этот nil увидеть, то есть не нужен сложный механизм извещений.

Код: Выделить всё
{
Sergey Bodrov (serbod@gmail.com) 2016
}
unit WeakRefs;

interface

type
  IWeakRef = interface
    ['{4C4419E1-7ADB-47A4-826A-61E03FBB4C84}']
    procedure _Clean;
    function IsAlive: Boolean;
    function GetOwner(): TObject;
  end;

  { Слабая ссылка, которая хранит ссылку на какой-то объект и висит в памяти,
    пока ее кто-то использует. Позволяет проверять, жив ли объект или нет. }
  TWeakRef = class(TInterfacedObject, IWeakRef)
  private
    FOwner: TObject;
  public
    constructor Create(AOwner: TObject); virtual;
    procedure _Clean;
    function IsAlive: Boolean;
    function GetOwner(): TObject;
  end;

  TWeakObject = class(TObject)
  protected
    FWeakRef: IWeakRef;
    function GetWeakRef(): IWeakRef; virtual;
  public
    procedure BeforeDestruction(); override;
    property WeakRef: IWeakRef read GetWeakRef;
  end;

implementation

{ TWeakRef }

constructor TWeakRef.Create(AOwner: TObject);
begin
  FOwner := AOwner;
end;

procedure TWeakRef._Clean();
begin
  FOwner := nil;
end;

function TWeakRef.GetOwner(): TObject;
begin
  Result := FOwner;
end;

function TWeakRef.IsAlive(): Boolean;
begin
  Result := Assigned(FOwner);
end;


{ TWeakObject }

procedure TWeakObject.BeforeDestruction;
begin
  if Assigned(FWeakRef) then
    FWeakRef._Clean();
  inherited;
end;

function TWeakObject.GetWeakRef: IWeakRef;
begin
  if FWeakRef = nil then
  begin
    FWeakRef := TWeakRef.Create(Self);
  end;
  Result := FWeakRef;
end;

end.


В коде выше TWeakObject это пример класса, использующего слабую ссылку. Можно в любой объект добавить пару методов и все.

А пример использования слабой ссылки:

Код: Выделить всё
type
  { некий ключ, у которого может быть владелец, который может вдруг исчезнуть }
  TKey = class(TObject)
  private
    FPersonWeakRef: IWeakRef;
    function GetPerson: TPerson;
    procedure SetPerson(const Value: TPerson);
  public
    { владелец ключа }
    property Person: TPerson read GetPerson write SetPerson;
  end;

function TKey.GetPerson: TPerson;
begin
  if Assigned(FPersonWeakRef) and FPersonWeakRef.IsAlive then
    Result := TPerson(FPersonWeakRef.GetOwner())
  else
    Result := nil;
end;

procedure TKey.SetPerson(const Value: TPerson);
begin
  if Assigned(Value) then
    FPersonWeakRef := Value.WeakRef
  else
    FPersonWeakRef := nil;
end;



Почитать на эту тему:
https://habrahabr.ru/post/219685/
https://habrahabr.ru/post/282035/
Аватара пользователя
serbod
постоялец
 
Сообщения: 449
Зарегистрирован: 16.09.2016 11:03:02
Откуда: Минск

Re: Типы данных

Сообщение Лекс Айрин » 19.12.2017 12:02:27

serbod, а цена вопроса? А то ведь можно так дойти, что увидишь как прорисовывается мир. И тогда проще будет использовать не то что тупые указатели и проверку ссылок на актуальность в объеме всей программы. Причем, для каждой платформы своими методами.
Аватара пользователя
Лекс Айрин
долгожитель
 
Сообщения: 5723
Зарегистрирован: 19.02.2013 16:54:51
Откуда: Волгоград

Re: Типы данных

Сообщение serbod » 19.12.2017 13:12:03

Лекс Айрин писал(а):а цена вопроса?

Как у "голого" TObject. Слабая ссылка создается один раз при первом обращении и висит себе в памяти, пока о ней помнят.

Согласен, что это варварство, рожать аж целый TObject ради одного указателя. Но увы, нормального механизма "слабых" указателей на класс не завезли.
Аватара пользователя
serbod
постоялец
 
Сообщения: 449
Зарегистрирован: 16.09.2016 11:03:02
Откуда: Минск

Re: Типы данных

Сообщение Лекс Айрин » 19.12.2017 13:38:57

serbod писал(а):Но увы, нормального механизма "слабых" указателей на класс не завезли.


обычная запись с ссылкой и счетчиком. С учетом существования у записей в современных версиях конструктора/деструктора/методов...
Ну или в самом объекте предусмотреть счетчик и функции типа Put/Push.
Аватара пользователя
Лекс Айрин
долгожитель
 
Сообщения: 5723
Зарегистрирован: 19.02.2013 16:54:51
Откуда: Волгоград

Re: Типы данных

Сообщение zub » 22.12.2017 16:15:47

Код: Выделить всё
ЧетоТам(@ЧетоТам1,@ЧетоТам2);

передача указателей на данные - самое стремное решение, использовать такое нужно если по другому ну совсем никак.
при использовании @ компилятор умывает руки из контроля типов параметров, всё это ложится на плечи "програмиста" и приводит к неизбежным глюкам
zub
долгожитель
 
Сообщения: 2884
Зарегистрирован: 14.11.2005 23:51:26

Re: Типы данных

Сообщение vitaly_l » 22.12.2017 16:31:11

zub писал(а):ЧетоТам(@ЧетоТам1,@ЧетоТам2);

передача указателей на данные - самое стремное решение, использовать такое нужно если по другому ну совсем никак.
при использовании @ компилятор умывает руки из контроля типов параметров, всё это ложится на плечи "програмиста" и приводит к неизбежным глюкам

А как тогда более правильно? (если можно в примерах)
Аватара пользователя
vitaly_l
долгожитель
 
Сообщения: 3333
Зарегистрирован: 31.01.2012 16:41:41

Re: Типы данных

Сообщение zub » 22.12.2017 17:01:20

>>А как тогда более правильно? (если можно в примерах)
модификаторы var, const, constref
zub
долгожитель
 
Сообщения: 2884
Зарегистрирован: 14.11.2005 23:51:26

Re: Типы данных

Сообщение vitaly_l » 22.12.2017 17:19:02

zub писал(а):модификаторы

А как тогда быть, если такого: ЧетоТам(@ЧетоТам1,@ЧетоТам2); - обращения требуют системные библиотеки?
Аватара пользователя
vitaly_l
долгожитель
 
Сообщения: 3333
Зарегистрирован: 31.01.2012 16:41:41

Re: Типы данных

Сообщение zub » 22.12.2017 17:20:07

смириться
zub
долгожитель
 
Сообщения: 2884
Зарегистрирован: 14.11.2005 23:51:26

Re: Типы данных

Сообщение Снег Север » 23.12.2017 09:17:36

vitaly_l писал(а):А как тогда быть, если такого: ЧетоТам(@ЧетоТам1,@ЧетоТам2); - обращения требуют системные библиотеки?
Да, интерфейсы к сишным библиотекам такое требуют постоянно. Приходится выкручиваться. Но в любых собственно паскалевских программах за использовать подобного надо отрубать руки по самую задницу.
Аватара пользователя
Снег Север
долгожитель
 
Сообщения: 2990
Зарегистрирован: 27.11.2007 16:14:47

Re: Типы данных

Сообщение Лекс Айрин » 23.12.2017 19:26:11

ссылки вообще стремное дело... но приходится использовать. А уж конструкции типа ЧетоТам(@ЧетоТам1,@ЧетоТам2) это классика программирования. Другое дело, что их надо как можно быстрее инкапсулировать и стараться туда больше не лезть без надобности.

В случае серьезной работы, использование объектов очень сильно замедляет работу программ... иногда на порядки. Пример -- компонент TMemo, который, при всей его примитивности очень уж тормозит при более-менее больших текстах (((
Аватара пользователя
Лекс Айрин
долгожитель
 
Сообщения: 5723
Зарегистрирован: 19.02.2013 16:54:51
Откуда: Волгоград

Re: Типы данных

Сообщение serbod » 23.12.2017 19:39:06

Снег Север писал(а):
vitaly_l писал(а):А как тогда быть, если такого: ЧетоТам(@ЧетоТам1,@ЧетоТам2); - обращения требуют системные библиотеки?
Да, интерфейсы к сишным библиотекам такое требуют постоянно. Приходится выкручиваться. Но в любых собственно паскалевских программах за использовать подобного надо отрубать руки по самую задницу.


const и var вполне годятся для сишных библиотек.

Добавлено спустя 5 минут 1 секунду:
Лекс Айрин писал(а):В случае серьезной работы, использование объектов очень сильно замедляет работу программ... иногда на порядки. Пример -- компонент TMemo, который, при всей его примитивности очень уж тормозит при более-менее больших текстах (((


Объекты языка не тормозят, там самые тормоза только при выделении-освобождении мапяти. А вот объекты GUI это целое приложение, управляемое сообщениями. Но там есть свои фокусы, например, для списков и таблиц можно использовать "owner data", и тогда отображение миллионов элементов будет тормозить не более, чем количество видимых на экране элементов.
Аватара пользователя
serbod
постоялец
 
Сообщения: 449
Зарегистрирован: 16.09.2016 11:03:02
Откуда: Минск

Re: Типы данных

Сообщение Cheb » 23.12.2017 19:46:27

Увы, тип class - это тупой указатель, без влияния на счетчик ссылок. Для переменных типа class счетчик ссылок не работает. Нужен тип переменной interface (которой присвоен экземпляр class), а это несколько ограничивает удобство пользования.

Чёзабред, наследуешь от IUnknown, делая всё ручками, или от TInterfacedObject, где всё уже сделано за нас - и класс становится со счётчиком ссылок, автоудаляющийся при присваивании nil последней ссылке на него.
Объяснил же уже, этот механизм чуть ли не с Дельфи 2 существует.
Цена вопроса - два лишних поля в экземпляре класса: ссылка на интерфейс и счётчик ссылок.

Пример -- компонент TMemo, который, при всей его примитивности очень уж тормозит

Вот потому и тормозит, что примитивный, и кпд у него ниже плинтуса.
А не потому, что он - класс.

Но в любых собственно паскалевских программах за использовать подобного надо отрубать руки по самую задницу.

Согласен с одной оговоркой: если пишешь API интерфейса между исполняемыми модулями с независимыми диспетчерами памяти - без указателей не обойтись. Потому что ни массив, ни строку не передашь: выйдет хряп-с.

const и var вполне годятся для сишных библиотек.

А вот за такое лапки оттяпывать надо уже пейсателю такой конверсии хидера.
!Внезапно! требуется передать NULL - и слов у тебя не остаётся, кроме матерных.
Аватара пользователя
Cheb
энтузиаст
 
Сообщения: 994
Зарегистрирован: 06.06.2005 15:54:34

Пред.След.

Вернуться в Free Pascal Compiler

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 5

Рейтинг@Mail.ru