Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

TList & records [D7, XP]


Страницы:   1 2

_Андрей ©   (2009-08-07 12:14:00) 

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

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

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 при добавлении каких-либо элементов в список находит в этом коде утечки памяти, подскажите, плиз, что не так делаю, может у кого-нить есть пример хранения записей в списке...


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

Kolan ©   (07.08.09 15:49) [30]

RTFS: db.pas TLookupList

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


Kolan   (2009-08-07 15:49:00) [2]

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

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

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


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

Kolan ©   (07.08.09 14:00) [24]

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


DVM   (2009-08-07 15:12:00) [4]


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

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


MsGuns   (2009-08-07 14:58:00) [5]

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

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


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

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

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


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

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

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


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

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

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


MsGuns   (2009-08-07 13:56:00) [9]

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

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


MsGuns   (2009-08-07 13:54:00) [10]

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

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

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


Kolan   (2009-08-07 13:52:00) [11]

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


Kolan   (2009-08-07 13:50:00) [12]

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

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

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


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


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


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

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


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


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


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

> _Андрей

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


Anatoly Podgoretsky   (2009-08-07 13:31:00) [15]

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

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


Best of the best   (2009-08-07 13:29:00) [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;


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

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

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


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

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

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


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

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


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


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


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

Dispose(Items[i])

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


Страницы:   1 2

Наверх

Титульная страница Поиск, карта сайта Написать письмо