Форум по Delphi программированию

Delphi Sources



Вернуться   Форум по Delphi программированию > Все о Delphi > [ "Начинающим" ]
Ник
Пароль
Регистрация <<         Правила форума         >> FAQ Пользователи Календарь Поиск Сообщения за сегодня Все разделы прочитаны

Ответ
 
Опции темы Поиск в этой теме Опции просмотра
  #1  
Старый 22.05.2023, 11:27
bubaeshka bubaeshka вне форума
Прохожий
 
Регистрация: 20.02.2016
Сообщения: 13
Версия Delphi: Delphi 7
Репутация: 10
По умолчанию Помогите с TPair

1. Не могу нигде найти информацию по этому самому пресловутому TPair. Что это такое? Применяются ли здесь конструкторы и деструкторы? Захотел себе такую штуку: TObjectList<TPair<integer,integer>> - компилятор заругался. Пропускает только простой TList<TPair<integer,integer>>. Но TList не очищает автоматически память. И я не могу понять, мне потом эти объекты TPair<integer,integer> - вручную удалять? или они примитивные? В документации вообще ничего нет толком.

2. Чтобы не плодить темы, спрошу второй вопрос здесь. К сожалению, как то я отстал от жизни совсем, хотя и "подучивал" другие ЯП, но в итоге... Сегодня набрёл на вот такую странную конструкцию:

Приведу здесь кусок кода:

Код:
var item:TDictionary<integer,integer>;
    zz,xx:TList<TPair<integer,integer>>;
    el:TPair<integer,integer>;
    Comparison:TComparison<TPair<integer,integer>>; 
begin
  item:=TDictionary<integer,integer>.Create;
  //очень подозрительная хрень
  Comparison:=
    function(const Left, Rigth: TPair<integer,integer>): integer
    begin 
      Result:=Left.Value-Rigth.Value; 
    end;
  //конец подозрительной хрени
  xx:=TList<TPair<integer,integer>>.Create(TComparer<TPair<integer,integer>>.Construct(Comparison));

Собственно... как я понимаю, я создаю в Comparison экземпляр класса TComparison, конструктору TList передаётся в параметре ссылка на интерфейс IComparer (интерфейсы? в Делфи? чё? ), которая есть результат функции Construct класса TComparer. Чё то я пока не допёр, как связаны Comparer и Comparison, но думаю допру, хотя если кто то ответит, я буду рад. Меня вот что волнует, как переменной Comparison можно присвоить функцию?

Код:
 //очень подозрительная хрень
  Comparison:=
    function(const Left, Rigth: TPair<integer,integer>): integer
    begin 
      Result:=Left.Value-Rigth.Value; 
    end;
  //конец подозрительной хрени

Почему у неё нет имени?

Видел подобные конструкции и в других языках, но не могу никак допереть как это работает. Код, украденный откуда то с просторов интернета, явно рабочий, но как можно писать код, работу которого, понимаешь только интуитивно? Что делает сама эта функция, мне объяснять не надо, тело функции может быть и не совсем верно, оно пока как "заглушка" (то есть вопрос, должна она возвращать только -1, 0, 1 или просто ноль, положительные и отрицательные значения, не важно какие - пока остаётся открытым). Что то писалось в интернетах по поводу проблем такого решения, типа классическое решение, с болтающейся в модуле непонятно куда пришитой, обычной функцией - работает быстрее и более безошибочно. Но мне не нравятся болтающиеся в модуле вспомогательные функции, которые не относятся ни к классу, ни являются подпроцедурами методов классов, бред какой то. В Делфи 7 процедура должна была быть вынесена за метод класса. Выглядела как мусор, а убери её и сортировки все накрылись, и правильная работа тоже....

Может есть какая то литература по современным возможностям делфи? Может и на русском даже есть (хотя сомнительно.....)? Или только док.эмбаркадеро.ком, стэковерфлоу и грабли?

Последний раз редактировалось bubaeshka, 22.05.2023 в 13:45.
Ответить с цитированием
  #2  
Старый 22.05.2023, 21:50
xchgeaxeax xchgeaxeax вне форума
Прохожий
 
Регистрация: 11.05.2023
Сообщения: 15
Версия Delphi: D7, Laz v2.2.6
Репутация: 10
По умолчанию

1) Нажимаете на Ctrl и с зажатой клавишей кликайте по TPair - комбинация быстрого перехода к описанию. Если не сработало, тогда ПКМ->Перейти к описанию (обычно самым первым пунктом).

2) Имя у неё есть Comparison
Ответить с цитированием
  #3  
Старый 23.05.2023, 02:32
lmikle lmikle вне форума
Модератор
 
Регистрация: 17.04.2008
Сообщения: 8,057
Версия Delphi: 7, XE3, 10.2
Репутация: 49089
По умолчанию

1. Нельзя использовать TObjectList с TPair просто потомк, что TPair это record, а не class:
https://docwiki.embarcadero.com/Libr...lections.TPair
2. Нет, ты не создаешь экзмепляр класса TComparison, бо как это не класс, а ссылка на функцию:
https://docwiki.embarcadero.com/Libr...ts.TComparison
А имени у нее нет, т.к. это одно из нововведений последних версий - анонимная функция.

Для простоты понимания шаблонов (или дженериков) просто представь, что компилятор сгенерирует соотв. код для каждого использованного щаблона.
Например, у тебя есть такой код:
Код:
var
  A : TPair<Integer,Integer>;
  B : TPair<String,String>;
А вот когда компилятор начнет это компилировать, то построит вот примерно что-то типа такого:
Код:
type
  TPairA = record
    Key : Integer;
    Valuie : Integer;
  endl

  TPairB = record
    Key : String;
    Value : String;
   end;

var
  A : TPairA;
  B : TPairB;
ЗЫ. Естественно, это упрощение. но для понимания свмое оно.
Ответить с цитированием
Этот пользователь сказал Спасибо lmikle за это полезное сообщение:
bubaeshka (23.05.2023)
  #4  
Старый 23.05.2023, 05:18
bubaeshka bubaeshka вне форума
Прохожий
 
Регистрация: 20.02.2016
Сообщения: 13
Версия Delphi: Delphi 7
Репутация: 10
По умолчанию

1. Я понимаю, что TPair это запись. То есть получается, что у меня примитивный тип, и после TList.Free в памяти ничего не останется? Просто нигде про это не сказано особо то. Про простые типы да, про массивы да, ещё там про что-то. +в запись мы можем засунуть и объекты, так ведь?

2. Да, пример мне понятен. И я бы даже сказал, что с дженериками стало в разы лучше! Я понимаю, что это, как это, с чем едят...

Вот про это я и хотел узнать поподробнее:
Цитата:
А имени у нее нет, т.к. это одно из нововведений последних версий - анонимная функция.

Попробую загуглить. К сожалению, инфы/учебников/материалов по Делфи стало весьма мало. Даже в буржуйском сегменте.

З.Ы. lmikle - ещё раз спасибо за наводку! "нововведений последних версий - анонимная функция". Теперь всё стало понятно. Просто мы зашвыриваем в конструктор TList целиком функцию, которую загоняем в переменную, прям кодом. Нашёлся хороший талмуд: http://pascal-study.blogspot.com/2012/03/delphi.html

Последний раз редактировалось bubaeshka, 23.05.2023 в 05:40.
Ответить с цитированием
  #5  
Старый 23.05.2023, 05:25
bubaeshka bubaeshka вне форума
Прохожий
 
Регистрация: 20.02.2016
Сообщения: 13
Версия Delphi: Delphi 7
Репутация: 10
По умолчанию

Цитата:
Сообщение от xchgeaxeax
1) Нажимаете на Ctrl и с зажатой клавишей кликайте по TPair - комбинация быстрого перехода к описанию. Если не сработало, тогда ПКМ->Перейти к описанию (обычно самым первым пунктом).

Документация была изучена под лупой, она скудна. Просто непонятно было к чему относятся записи. Теперь становится понятно, к примитивным типам.
Хотя исторически, в Object Pascal записи и предшествовали классам. И TPair примитивный тип. Ну видимо до тех пор, пока в его полях, не поселились объекты.

Вообще, в своё время, пытался изучить жабу. Сейчас вижу, что оттуда скочевало в Делфи многое, очень многое. Одно непонятно, почему Делфи не стрельнул, в последнее время... Возможностей стало вагон.
Ответить с цитированием
  #6  
Старый 23.05.2023, 14:10
xchgeaxeax xchgeaxeax вне форума
Прохожий
 
Регистрация: 11.05.2023
Сообщения: 15
Версия Delphi: D7, Laz v2.2.6
Репутация: 10
По умолчанию

Цитата:
Документация была изучена под лупой, она скудна.
Это должно перебросить не на документацию, а на код, который описывает данное имя/функцию. Так можно понять почему не работает. Например, щелчок по TPair должен перебросить на
Код:
  TPair<TKey,TValue> = record
    Key: TKey;
    Value: TValue;
    constructor Create(const AKey: TKey; const AValue: TValue);
  end;
в соответствующем модуле. Так можно понять, что это не класс и он не может ничего из возможностей класса.
Ответить с цитированием
  #7  
Старый 23.05.2023, 18:03
lmikle lmikle вне форума
Модератор
 
Регистрация: 17.04.2008
Сообщения: 8,057
Версия Delphi: 7, XE3, 10.2
Репутация: 49089
По умолчанию

Ну тогда для тебя плохая новость - да, при очистке TList<TPair<...>> данные останутся в памяти. Можно схитрить и просто обернуть TPair в класс и хранить уже его объекты в TObjectList.
Про анонимные функции - по сути это синтаксический сахар, без них вполне можно обойтись, более того, если тебе одна и та же функция нужно в нескольких местах, то как раз лучше обойтись без анонимных фнункций нежели копировать один и тот же код в нескольких местах.
Ответить с цитированием
  #8  
Старый 24.05.2023, 11:37
bubaeshka bubaeshka вне форума
Прохожий
 
Регистрация: 20.02.2016
Сообщения: 13
Версия Delphi: Delphi 7
Репутация: 10
По умолчанию

Так всё-таки? Останутся ли TPair в памяти, если его параметры - простые типы? Сейчас столкнулся с проблемой. Компилятор считает TPair - константой. Не даёт изменять значение Value в списке.

Код:
zz[k].Value:=zz[k].Value-1;

При секции в Var следующего вида

Код:
zz,xx:TList<TPair<integer,integer>>;

Выдаёт ошибку: E2064 Left side cannot be assigned to

Мне очень удобно работать с TPair, как с простым типом. Если он действительно простой тип. В прошлой версии программы, я использовал вспомогательный класс. С простым типом, типа записи, если действительно не требуется очистки памяти, мне работать проще и быстрее. И мне не надо там методов, мне просто нужно хранилище оперативных данных, я мог вообще воспользоваться массивом обычным, но мне надо хранить кроме значения, ещё и ключ, к которому он относится.

Это я видел:
Код:
TPair<TKey,TValue> = record
  Key: TKey;
  Value: TValue;
  constructor Create(const AKey: TKey; const AValue: TValue);
end;

...блин. Вот же ответ то. Под носом. Ну, под носом труднее всего найти... Это очень плохо, что TPair сделана константой.... Удобный тип то, был...

Я конечно извернулся, удалением элемента и вставкой нового, но выглядит это как какой-то костыль....

Цитата:
Ну тогда для тебя плохая новость - да, при очистке TList<TPair<...>> данные останутся в памяти. Можно схитрить и просто обернуть TPair в класс и хранить уже его объекты в TObjectList.
Про анонимные функции - по сути это синтаксический сахар, без них вполне можно обойтись, более того, если тебе одна и та же функция нужно в нескольких местах, то как раз лучше обойтись без анонимных фнункций нежели копировать один и тот же код в нескольких местах.

Не хочу я класс, хочу запись. Вот здесь натолкнулся на то, что записи вроде как сами чистятся: https://www.cyberforum.ru/delphi-beg...ead952981.html

Последний раз редактировалось bubaeshka, 24.05.2023 в 12:34.
Ответить с цитированием
  #9  
Старый 24.05.2023, 18:50
lmikle lmikle вне форума
Модератор
 
Регистрация: 17.04.2008
Сообщения: 8,057
Версия Delphi: 7, XE3, 10.2
Репутация: 49089
По умолчанию

Да нет, не константа. То, что ты видишь const в конструкторе относится к методу передачи параметров в кнструктор и только.

Не уверен, что записи будут удаляться в случае TList. В случае массивва - да, все почистится само, а вот с TList могут быть проблемы...
Ответить с цитированием
  #10  
Старый 24.05.2023, 19:13
lmikle lmikle вне форума
Модератор
 
Регистрация: 17.04.2008
Сообщения: 8,057
Версия Delphi: 7, XE3, 10.2
Репутация: 49089
По умолчанию

Да, сейчас проверил, прямое изменение не работает. Что-то там, видимо, не то с дженериками. Зато вот так работает:
Код:
procedure TForm1.Button1Click(Sender: TObject);
var
  l : TList<TPair<Integer,Integer>>;
  p : TPair<Integer,Integer>;
begin
  l := TList<TPair<Integer,Integer>>.Create;
  Try
    l.Add(TPair<Integer,Integer>.Create(1,1));
    ShowMessage(Format('Item 0: Key = %d, Value = %d',[l[0].Key, l[0].Value]));
    p := l[0];
    p.Value := p.Value + 1;
    l[0] := p;
    ShowMessage(Format('Item 0: Key = %d, Value = %d',[l[0].Key, l[0].Value]));
  Finally
    l.Free;
  End;
end;
Ответить с цитированием
Этот пользователь сказал Спасибо lmikle за это полезное сообщение:
bubaeshka (25.05.2023)
  #11  
Старый 24.05.2023, 23:51
xchgeaxeax xchgeaxeax вне форума
Прохожий
 
Регистрация: 11.05.2023
Сообщения: 15
Версия Delphi: D7, Laz v2.2.6
Репутация: 10
По умолчанию

Ещё можете сделать это в циклах и посмотреть как будет прирастать память программы.
Код:
procedure TForm1.Button1Click(Sender: TObject);
var
  l : TList<TPair<Integer,Integer>>;
  p : TPair<Integer,Integer>;
  i, j: Integer;
begin
  for j := 0 to 99999 do begin
    l := TList<TPair<Integer,Integer>>.Create;
    Try
      for i := 0 to 99999 do
        l.Add(TPair<Integer,Integer>.Create(i,2*i));
    Finally
      l.Free;
    End;
    Sleep(100); // Чтобы насладиться моментом
  end;
end;
Ответить с цитированием
  #12  
Старый 25.05.2023, 04:24
lmikle lmikle вне форума
Модератор
 
Регистрация: 17.04.2008
Сообщения: 8,057
Версия Delphi: 7, XE3, 10.2
Репутация: 49089
По умолчанию

Ну, тут вопрос сложный.
Менеджер памяти ее не сразу отдает. Так что тут вопрос интересный.
Для уточнения просто включить контроль утечек памяти - при закрытии программы менеджер памяти сам скажет есть ли утечки или нет.
Ответить с цитированием
  #13  
Старый 25.05.2023, 05:35
bubaeshka bubaeshka вне форума
Прохожий
 
Регистрация: 20.02.2016
Сообщения: 13
Версия Delphi: Delphi 7
Репутация: 10
По умолчанию

Цитата:
Сообщение от lmikle
Да, сейчас проверил, прямое изменение не работает. Что-то там, видимо, не то с дженериками. Зато вот так работает:
Код:
procedure TForm1.Button1Click(Sender: TObject);
var
  l : TList<TPair<Integer,Integer>>;
  p : TPair<Integer,Integer>;
begin
  l := TList<TPair<Integer,Integer>>.Create;
  Try
    l.Add(TPair<Integer,Integer>.Create(1,1));
    ShowMessage(Format('Item 0: Key = %d, Value = %d',[l[0].Key, l[0].Value]));
    p := l[0];
    p.Value := p.Value + 1;
    l[0] := p;
    ShowMessage(Format('Item 0: Key = %d, Value = %d',[l[0].Key, l[0].Value]));
  Finally
    l.Free;
  End;
end;

Обана! Сейчас попробую.
Ответить с цитированием
  #14  
Старый 25.05.2023, 05:36
bubaeshka bubaeshka вне форума
Прохожий
 
Регистрация: 20.02.2016
Сообщения: 13
Версия Delphi: Delphi 7
Репутация: 10
По умолчанию

Цитата:
Сообщение от lmikle
Ну, тут вопрос сложный.
Менеджер памяти ее не сразу отдает. Так что тут вопрос интересный.
Для уточнения просто включить контроль утечек памяти - при закрытии программы менеджер памяти сам скажет есть ли утечки или нет.

Я как то пользовался FastMM, его же ещё прикручивать надо. А вы каким пользуетесь? А встроенный есть?
Ответить с цитированием
  #15  
Старый 25.05.2023, 18:05
lmikle lmikle вне форума
Модератор
 
Регистрация: 17.04.2008
Сообщения: 8,057
Версия Delphi: 7, XE3, 10.2
Репутация: 49089
По умолчанию

А в последних версиях Delphi FastMM и есть менеджер памяти по умолчанию Если не ошибаюсь, просто добавь в любом модуле вот такую штуку:
Код:
initialization
  ReportMemoryLeaksOnShutdown := True;
Ответить с цитированием
Ответ


Delphi Sources

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск
Опции просмотра

Ваши права в разделе
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы не можете редактировать сообщения

BB-коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход


Часовой пояс GMT +3, время: 17:35.


 

Сайт

Форум

FAQ

RSS лента

Прочее

 

Copyright © Форум "Delphi Sources" by BrokenByte Software, 2004-2023

ВКонтакте   Facebook   Twitter