|
#1
|
|||
|
|||
Помогите с 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
|
|||
|
|||
1) Нажимаете на Ctrl и с зажатой клавишей кликайте по TPair - комбинация быстрого перехода к описанию. Если не сработало, тогда ПКМ->Перейти к описанию (обычно самым первым пунктом).
2) Имя у неё есть Comparison |
#3
|
|||
|
|||
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
|
|||
|
|||
1. Я понимаю, что TPair это запись. То есть получается, что у меня примитивный тип, и после TList.Free в памяти ничего не останется? Просто нигде про это не сказано особо то. Про простые типы да, про массивы да, ещё там про что-то. +в запись мы можем засунуть и объекты, так ведь?
2. Да, пример мне понятен. И я бы даже сказал, что с дженериками стало в разы лучше! Я понимаю, что это, как это, с чем едят... Вот про это я и хотел узнать поподробнее: Цитата:
Попробую загуглить. К сожалению, инфы/учебников/материалов по Делфи стало весьма мало. Даже в буржуйском сегменте. З.Ы. lmikle - ещё раз спасибо за наводку! "нововведений последних версий - анонимная функция". Теперь всё стало понятно. Просто мы зашвыриваем в конструктор TList целиком функцию, которую загоняем в переменную, прям кодом. Нашёлся хороший талмуд: http://pascal-study.blogspot.com/2012/03/delphi.html Последний раз редактировалось bubaeshka, 23.05.2023 в 05:40. |
#5
|
|||
|
|||
Цитата:
Документация была изучена под лупой, она скудна. Просто непонятно было к чему относятся записи. Теперь становится понятно, к примитивным типам. Хотя исторически, в Object Pascal записи и предшествовали классам. И TPair примитивный тип. Ну видимо до тех пор, пока в его полях, не поселились объекты. Вообще, в своё время, пытался изучить жабу. Сейчас вижу, что оттуда скочевало в Делфи многое, очень многое. Одно непонятно, почему Делфи не стрельнул, в последнее время... Возможностей стало вагон. |
#6
|
|||
|
|||
Цитата:
Код:
TPair<TKey,TValue> = record Key: TKey; Value: TValue; constructor Create(const AKey: TKey; const AValue: TValue); end; |
#7
|
|||
|
|||
Ну тогда для тебя плохая новость - да, при очистке TList<TPair<...>> данные останутся в памяти. Можно схитрить и просто обернуть TPair в класс и хранить уже его объекты в TObjectList.
Про анонимные функции - по сути это синтаксический сахар, без них вполне можно обойтись, более того, если тебе одна и та же функция нужно в нескольких местах, то как раз лучше обойтись без анонимных фнункций нежели копировать один и тот же код в нескольких местах. |
#8
|
|||
|
|||
Так всё-таки? Останутся ли 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 сделана константой.... Удобный тип то, был... Я конечно извернулся, удалением элемента и вставкой нового, но выглядит это как какой-то костыль.... Цитата:
Не хочу я класс, хочу запись. Вот здесь натолкнулся на то, что записи вроде как сами чистятся: https://www.cyberforum.ru/delphi-beg...ead952981.html Последний раз редактировалось bubaeshka, 24.05.2023 в 12:34. |
#9
|
|||
|
|||
Да нет, не константа. То, что ты видишь const в конструкторе относится к методу передачи параметров в кнструктор и только.
Не уверен, что записи будут удаляться в случае TList. В случае массивва - да, все почистится само, а вот с TList могут быть проблемы... |
#10
|
|||
|
|||
Да, сейчас проверил, прямое изменение не работает. Что-то там, видимо, не то с дженериками. Зато вот так работает:
Код:
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
|
|||
|
|||
Ещё можете сделать это в циклах и посмотреть как будет прирастать память программы.
Код:
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
|
|||
|
|||
Ну, тут вопрос сложный.
Менеджер памяти ее не сразу отдает. Так что тут вопрос интересный. Для уточнения просто включить контроль утечек памяти - при закрытии программы менеджер памяти сам скажет есть ли утечки или нет. |
#13
|
|||
|
|||
Цитата:
Обана! Сейчас попробую. |
#14
|
|||
|
|||
Цитата:
Я как то пользовался FastMM, его же ещё прикручивать надо. А вы каким пользуетесь? А встроенный есть? |
#15
|
|||
|
|||
А в последних версиях Delphi FastMM и есть менеджер памяти по умолчанию Если не ошибаюсь, просто добавь в любом модуле вот такую штуку:
Код:
initialization ReportMemoryLeaksOnShutdown := True; |