Страница 1 из 2
Как правильно освобождать память?
Добавлено: 30.08.2015 19:12:00
xterro
Доброго времени суток, что-то я совсем запутался в этих указателях, и не могу банально очистить память после использования

Есть класс:
Код: Выделить всё
tpolygon = class
private
fvertex : tlist;
fholes : tlist;
ffill_hash : tlist;
....
end;
Элементами списка fvertex являются записи типа:
Добавляю так:
Код: Выделить всё
procedure tpolygon.add_vertex(x : real; y : real);
var
p : ^tpointf;
begin
new(p);
p^.x := x;
p^.y := y;
fvertex.add(p);
end;
И в заключении деструктор:
Код: Выделить всё
destructor tpolygon.destroy();
var
i : integer;
begin
for i := 0 to fvertex.count - 1 do
begin
tpointf(fvertex[i]).free; // здесь получаю ошибку: trpolygon.pas(116,9) Error: Illegal type conversion: "Pointer" to "TPointF"
// здесь же пытался почиститься так: dispose(tpointf(fvertex[i])); ---> ошибка та же самая(если убрать приведение к tpointf то ругается, мол Error: use of NEW or DISPOSE is not possible for untyped pointers
)
end;
fvertex.destroy();
for i := 0 to fholes.count - 1 do
tpolygon(fholes[i]).free;
fholes.destroy();
for i := 0 to ffill_hash.count - 1 do
tyitem(ffill_hash[i]).free;
ffill_hash.destroy();
end;
Как всё таки правильно удалять объекты и освобождать память?

Re: Как правильно освобождать память?
Добавлено: 30.08.2015 19:27:00
kazalex
Код: Выделить всё
type PPointF = ^TPointF;
...
Dispose(PPointF(fvertex[i]));
Re: Как правильно освобождать память?
Добавлено: 30.08.2015 19:36:19
Sharfik
Ты сам себя запутал, загнав все в одну строку.
Код: Выделить всё
destructor tpolygon.destroy();
var
i : integer;
p : ^tpointf;
begin
for i := 0 to fvertex.count - 1 do
begin
//методу free тут не место, это процедура классов, а не записей.
p :=fvertex[i]; //Если не ошибаюсь так должно работать
dispose(p);
end;
fvertex.Free;
end;
PS: Грабли - Использовать TList удобно, но он медленнее чем массивы. Лучше потратить время и написать несколько процедур по хранению всего этого в массиве.
Добавлено спустя 1 минуту 5 секунд:kazalex писал(а):Код: Выделить всё
type PPointF = ^TPointF;
...
Dispose(PPointF(fvertex[i]));
kazalex, у него нет объявления
Код: Выделить всё
PPointF=^tpointf; ///Это тогда в типах добавить надо, если как kazalex написал.
Re: Как правильно освобождать память?
Добавлено: 30.08.2015 20:46:54
xterro
Понял свою ошибку, спасибо ) Оказывается надо приводить не просто к типу PPointF, а к указателю на него. Я думал компилятор сам всё сделает как надо
Ещё такой вопрос, вот в данном случае, в списке я храню record и объекты(в двух других списках), для них в destroy() соотсвественно вызываю dispose(record) и free(для объектов).
А если бы у меня в списке хранились не записи, а простые числа, скажем типа real, мне всё равно для каждого элемента списка надо было бы вызывать dispose? или можно было бы вызвать просто для всего списка free(fvertex.free())?
Re: Как правильно освобождать память?
Добавлено: 30.08.2015 21:00:44
zub
Не используй TList для мелочи, используй простые массивы или какиенибудь generic надстройки над ними
Re: Как правильно освобождать память?
Добавлено: 30.08.2015 21:07:31
xterro
zub писал(а):Не используй TList для мелочи, используй простые массивы или какиенибудь generic надстройки над ними
Я зараннее не знаю сколько точек или объектов у меня будет. Или делать каждый раз при добавлении записи в массив делать SetLength(arr, length(arr)+1) ? А это по феншую?
Ведь в массиве так же будут лежать указатели на объекты или на записи.
P.S. В деструкторе так же нужно будет пробегать по массиву и для каждого элемента вызывать free/dispose, или достаточно будет сделать что-то типа dispose(arr) и весь массив с содержимым почиститься?
Re: Как правильно освобождать память?
Добавлено: 30.08.2015 21:21:12
zub
>>SetLength(arr, length(arr)+1) ? А это по феншую?
если тебе надо добавить всего один элемент, то по феншую. Если ты так хочешь добавить 100500 элементов - то нет, по феншую будет SetLength(arr,сколько_надо) и потом работать с уже выделенными элементами
>>Ведь в массиве так же будут лежать указатели на объекты или на записи.
В массиве будет лежать то что тебе надо - хочешь сами данные, хочешь указатели. Естественно если ты хочешь сделать массив разнотипных элементов - придется делать на указателях, если однотипных то array of PointF - это массив элементов PointF, а не указателей на PointF
>>или достаточно будет сделать что-то типа dispose(arr) и весь массив с содержимым почиститься?
В простых случаях достаточно SetLength(arr, 0)
Re: Как правильно освобождать память?
Добавлено: 30.08.2015 21:23:52
xterro
Теперь понятней стало, спасибо

Re: Как правильно освобождать память?
Добавлено: 31.08.2015 00:58:54
wavebvg
Sharfik писал(а):Использовать TList удобно, но он медленнее чем массивы.
Это как? Проверки на границы? Не пользуйтесь методами с проверкой границ. Больше тормозить нечему, а
Capacity решит проблемы с тормозами при выделением памяти (в 90% случаев, если неизвестен размер списка в результате, это решает проблему с памятью).
Re: Как правильно освобождать память?
Добавлено: 31.08.2015 01:33:26
Sharfik
wavebvg писал(а):Это как?
Обход массива быстрее обхода класса на основе tlist и выше.
wavebvg писал(а):Проверки на границы?
Не знаком.
wavebvg писал(а):Capacity решит проблемы с тормозами при выделением памяти
Пробовал, разницы ноль было.
Re: Как правильно освобождать память?
Добавлено: 31.08.2015 01:52:26
zub
>>Это как? Проверки на границы? Не пользуйтесь методами с проверкой границ. Больше тормозить нечему
Тормозить какраз есть чему, tlist это массив указателей на данные - лишние разименования указателей, лишние выделения памяти для элементов.
ИМХО за применение tlist как у ТС для простых структур данных надо двойки ставить))
Re: Как правильно освобождать память?
Добавлено: 31.08.2015 07:55:00
xterro
Тут просто удобнее использовать списки. Можно конечно и массив взять, но получится разброд и шатание: один член класса - массив, второй, третий - список, как-то не айс имхо.
Я изначально не знаю сколько раз мне придётся вызывать
а ведь в случае массива, в каждом из этих вызовов пришлось бы делать setLength(), которая будет перевыделять память/копировать из старого массива(блока памяти) в новый, не нивелирует ли это, преимущество массивов перед списком? вроде как памяти занимать будет меньше, но и на производительность повлияет(операции перевыделения памяти).
Если бы я заранее знал сколько у меня будет точек, то да, без проблем, выделил нужное количество памяти и заполнил. Но не думаю что точек и полигонов будет настолько много, что придётся сильно оптимизировать

Re: Как правильно освобождать память?
Добавлено: 31.08.2015 08:57:20
Снег Север
xterro писал(а):а ведь в случае массива, в каждом из этих вызовов пришлось бы делать setLength()
увеличиваете массив не на один элемент, а на некоторую порцию, размер которой зависит от примерной оценки максимального размера массива и только при исчерпании свободного места
Re: Как правильно освобождать память?
Добавлено: 31.08.2015 11:03:46
Kitayets
Если нотификация списка не требуется - эффективнее использовать TFPList (так в вики на сайте лазаруса написано).
Чтобы поменьше "кастов" было, если в списке одинаковые объекты - то дженериковую версию списка удобнее использовать TFPGList.
Динамические массивы - не особо быстрые. Выделения памяти - довольно долгие + после добавки размера (setLenght) runtime библиотека может переместить весь массив в другое место - с копированием всего содержимого. Кроме того, что это затратно по времени + все указатели на элементы массива становятся не валидными. Медленные проверки границ тоже. По этому всяких развесистых структур на дин. массивах лучше избегать ИМХО.
короче если нужен быстрый произвольны доступ к элементам, при этом с самой структурой данных ничего делать не надо (сортировка, произвольная вставка элементов с изм. размера) - используй массив (если заранее размер не известен, но в течении работы программы сильно/часто изменяться не будет - динамические), иначе - списки.
Re: Как правильно освобождать память?
Добавлено: 31.08.2015 15:36:45
Vadim
Kitayets писал(а):эффективнее использовать TFPList
У TList'а хранилище как раз и есть TFPList.

Хотя, конечно, конструкция уже получается трёхэтажная.
