Форум: "Начинающим";
Текущий архив: 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