Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Начинающим";
Текущий архив: 2009.10.11;
Скачать: [xml.tar.bz2];

Вниз

TList & records   Найти похожие ветки 

 
_Андрей   (2009-08-07 12:14) [0]

Здравствуйте.

Для хранения списка таких вот записей:

type
 PRasEntry = ^TRasEntry;
 TRasEntry = record
 Name, User, Pswd, Phone: string;
end;


создал наследника TList:

type TRasList = class(TList)
 private
   function ReadItem(index: integer): TRasEntry;
   procedure WriteItem(index: integer; const Value: TRasEntry);
 public
   procedure AddItem(RasEntry: TRasEntry); overload;
   procedure AddItem(Name, User, Pswd, Phone: string); overload;
   property RasItems[index: integer]: TRasEntry read ReadItem write WriteItem;
   destructor Destroy; override;
end;

Вот его реализация:

procedure TRasList.AddItem(RasEntry: TRasEntry);
var P: PRasEntry;
begin
 New(P);
 P^ := RasEntry;
 Add(P)
end;

procedure TRasList.AddItem(Name, User, Pswd, Phone: string);
var P: PRasEntry;
begin
 New(P);
 P^.Name := Name; P^.User := User; P^.Pswd := Pswd; P^.Phone := Phone;
 Add(P)
end;

function TRasList.ReadItem(index: integer): TRasEntry;
begin
 if (index >=0) and (index <= Count-1) then Result := TRasEntry(Items[index]^)
end;

procedure TRasList.WriteItem(index: integer; const Value: TRasEntry);
begin
 if (index >=0) and (index <= Count-1) then
   begin
   TRasEntry(Items[index]^).Name := Value.Name;
   TRasEntry(Items[index]^).User := Value.User;
   TRasEntry(Items[index]^).Pswd := Value.Pswd;
   TRasEntry(Items[index]^).Phone := Value.Phone
   end
end;

destructor TRasList.Destroy;
var i: integer;
begin
 for i:=Count-1 downto 0 do
   begin
   Dispose(Items[i]);
   Delete(i)
   end;
 inherited
end;


Проблема в том что FastMM при добавлении каких-либо элементов в список находит в этом коде утечки памяти, подскажите, плиз, что не так делаю, может у кого-нить есть пример хранения записей в списке...


 
Kolan ©   (2009-08-07 12:27) [1]

Интересно, почему вы не использовали объекты?


 
_Андрей   (2009-08-07 12:35) [2]


> Kolan ©   (07.08.09 12:27) [1]
> Интересно, почему вы не использовали объекты?


В смысле? О каких объектах речь?


 
DVM ©   (2009-08-07 12:46) [3]


> Проблема в том что FastMM при добавлении каких-либо элементов
> в список находит в этом коде утечки памяти, подскажите,
> плиз, что не так делаю


> Dispose(Items[i]);

замени на

Dispose(PRasEntry (Items[i]));


 
Игорь Шевченко ©   (2009-08-07 12:47) [4]


> Dispose(Items[i]);


Dispose(PRasEntry(Items[i]))


 
Юрий Зотов ©   (2009-08-07 12:58) [5]

> _Андрей   (07.08.09 12:35) [2]

В деструкторе (точнее, в Dispose), чтобы правильно освободить память и финализировать строки записей нужно явно задать тип указателя (см. [3] и [4]). Иначе используется нетипизированный указатель (поскольку в TList они и есть) и строки записей могут "повиснуть".

А проще было бы вместо record использовать class, а вместо TList - TObjectList.


 
Юрий Зотов ©   (2009-08-07 13:00) [6]

Вдогонку - и если этот class наследовать от TCollectionItem, то вместо списка можно использовать коллекцию. Что лучше - зависит от задачи.


 
_Андрей   (2009-08-07 13:03) [7]

Ага), больше FastMM не ругается, здорово, большущее спасибо..!
А в чём была проблема, понятно в опщем что в 1-м случае освобождалась не вся память, но вот что конкретно дало приведение типа (PRasEntry(Items[i]))? Объясните, если нетрудно, несведущему...


 
_Андрей   (2009-08-07 13:07) [8]


> Юрий Зотов ©   (07.08.09 12:58) [5]


А как Dispose узнаёт "сколько" памяти необходимо освободить?


> А проще было бы вместо record использовать class, а вместо
> TList - TObjectList.


Мне кажеться это здесь лишнее, записей здесь более чем достаточно, 4 строчки и всё, вот если бы объект был посложнее...


 
Медвежонок Пятачок ©   (2009-08-07 13:13) [9]

Ну так здесь и сам наследник TList тоже лишний.
Хватит самого тлиста и обычной процедуры ClearMyList


 
MBo ©   (2009-08-07 13:15) [10]

>А как Dispose узнаёт "сколько" памяти необходимо освободить?
это "умная" процедура, ей неявно передается информация о типе, и она до освобождения непосредственно выделенной памяти (в данном случае 16 байт под указатели на строки) выполняет Finalize для корректного освобождения (финализации) динамических типов


 
_Андрей   (2009-08-07 13:18) [11]


> Медвежонок Пятачок ©   (07.08.09 13:13) [9]


Наследний был нужен для того, чтобы добавить процедуры добавления новых записей, так намного удобней (много где потом это используется), в опщем лучше здесь сделать здесь чуть больше чтоб потом в самой проге код не захламлять, достаточно написать, например:

RasList.AddItem("mts", "mts", "mts", "pw8w9707070707") и всё...


 
_Андрей   (2009-08-07 13:20) [12]


> MBo ©   (07.08.09 13:15) [10]


А что тогда делает:

Dispose(Items[i])

Осовбождает только часть или вообще ничего?


 
MBo ©   (2009-08-07 13:23) [13]

Dispose(Items[i]) передается нетипизированный указатель, и про него системе известно только то, что по этому адресу выделено 16 байт


 
Юрий Зотов ©   (2009-08-07 13:24) [14]

> _Андрей   (07.08.09 13:20) [12]

Освобождает память, занятую записью, но не освобождает память, занятую строками этой записи (name и пр.).


 
Юрий Зотов ©   (2009-08-07 13:28) [15]

> _Андрей   (07.08.09 13:20) [12]

Длиные строки Delphi - это указатели. Поэтому Ваша запись содержит 4 указателя и занимает 16 байт, независимо от длины ее строк. Сами же строки (то есть, их тела) хранятся в другом месте.


 
Best of the best   (2009-08-07 13:29) [16]


> destructor TRasList.Destroy;
> var i: integer;
> begin
>  for i:=Count-1 downto 0 do
>    begin
>    Dispose(Items[i]);
>    Delete(i)
>    end;
>  inherited
> end;
>



Вместо вышеописанного правильнее будет перекрыть метод Notify:

 
protected
   procedure Notify(Ptr: Pointer; Action: TListNotification); override;



procedure TRasList.Notify(Ptr: Pointer; Action: TListNotification);
begin
 case Action of
   lnDeleted: Dispose(PRasEntry(Ptr));
 end;
end;


 
Anatoly Podgoretsky ©   (2009-08-07 13:31) [17]

> _Андрей  (07.08.2009 13:03:07)  [7]

Знание, что это указатель на TRasEntry и что его надо финализировать.


 
Юрий Зотов ©   (2009-08-07 13:39) [18]

> _Андрей

Кстати, в [16] дело сказано. Иначе будет неверно работать удаление из списка (Delete и Remove).


 
_Андрей   (2009-08-07 13:48) [19]


> Юрий Зотов ©   (07.08.09 13:39) [18]


Имеется ввиду Delete и Remove класса TList, да?

То есть нужно, например, добавить функцию:


> TRasList.RasDelete(Index: integer);
> begin
>    Dispose(PRasEntry(Items(Index)));
>    Delete(Index)
> end


Хотя вариант лучшего "покруче" будет...


 
Kolan ©   (2009-08-07 13:50) [20]

Я об обычных объектах, которые наследники TObject.

То есть почему бы не написать так:
TRasEntry = class
...

и не использовать TObjectList?


 
Kolan ©   (2009-08-07 13:52) [21]

Да, а не счет того, что этот набор данных не достоин стать объектом из-за того, что он слишком прост, то стоит только сделать объект, как найдутся методы, которые удобно поместить именно в нем. Про это рассказывается в книге Мартина Фаулера «Рефакторинг».


 
MsGuns ©   (2009-08-07 13:54) [22]

> Best of the best   (07.08.09 13:29) [16]

А почему бы не так:

while Count>0 do
 begin
   Dispose(PRasEntry(Items[0]);
   Delete(0);  
 end;
inherited


 
MsGuns ©   (2009-08-07 13:56) [23]

>Kolan ©   (07.08.09 13:50) [20]

Потому что для простых объектов-записей (типа сабжа) писАть классы - только загромождать код


 
Kolan ©   (2009-08-07 14:00) [24]

MsGuns, вы про такое загромождение?

TRasEntry = class
public
 Name, User, Pswd, Phone: string;
end;


 
Юрий Зотов ©   (2009-08-07 14:07) [25]

> MsGuns ©   (07.08.09 13:56) [23]

[24] загромождает код куда меньше, чем [0]. Потому что не требует ни единой строчки дополнительного кода.


 
Юрий Зотов ©   (2009-08-07 14:11) [26]

> _Андрей   (07.08.09 13:48) [19]

Не нужно ничего добавлять, только код загромождаться будет. Уберите деструктор и заместите Notify, вот и все. А еще лучше - прислушаться к советам и использовать класс вместо записи, так проще и безопаснее.


 
MsGuns ©   (2009-08-07 14:58) [27]

>Kolan ©   (07.08.09 14:00) [24]

Действительно:)
А я ж думал с пропертями вместо простых переменных, конструкторами-деструкторами :)


 
DVM ©   (2009-08-07 15:12) [28]


> TRasEntry = class
> public
>  Name, User, Pswd, Phone: string;
> end;

В таких классах нет смысла. Класс ради класса.


 
Игорь Шевченко ©   (2009-08-07 15:13) [29]

Kolan ©   (07.08.09 14:00) [24]

Ты ж Фаулера учил, который пишет, что от таких классов надо избавляться ? А сам рекомендуешь, как же так ? :)


 
Kolan ©   (2009-08-07 15:49) [30]

Игор, я помню про то, что такие классы, без инкапсуляции, лучше не делать. Но. 1. Запись не лучше.
2. Для записи, в данном случае, приходится городить огород с удалением и прочим, а с классами такой проблемы нет.

То есть я думаю, что в сабже можно сделать рефакторинг в два этапа. На первом этапе просто заменить запись на класс и избавиться от геморроя с указателями и памятью. А когда автору понадобится модифицировать класс (если понадобится), он сделает нормальную инкапсуляцию, заменив поля одноименными свойствами.

То есть с классом у него сейчас будет меньше трудностей, а в будущем больше возможностей.


 
Игорь Шевченко ©   (2009-08-07 16:30) [31]

Kolan ©   (07.08.09 15:49) [30]

RTFS: db.pas TLookupList

Не сделали классом. Ибо нефиг



Страницы: 1 вся ветка

Форум: "Начинающим";
Текущий архив: 2009.10.11;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.52 MB
Время: 0.007 c
15-1249924835
@!!ex
2009-08-10 21:20
2009.10.11
Где найти книг во вселенной BattleTech?


1-1219124183
checkmate-maker
2008-08-19 09:36
2009.10.11
Редактор с картинками


2-1249564584
leonidus
2009-08-06 17:16
2009.10.11
Вопрос по механизму работы application.ProcessMessages


3-1227848167
belmol
2008-11-28 07:56
2009.10.11
сложная выборка


15-1248075284
xayam
2009-07-20 11:34
2009.10.11
Настройка Apache, htaccess





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский