Как правильно освобождать память?

Общие вопросы программирования, алгоритмы и т.п.

Модератор: Модераторы

Как правильно освобождать память?

Сообщение xterro » 30.08.2015 20:12:00

Доброго времени суток, что-то я совсем запутался в этих указателях, и не могу банально очистить память после использования :(
Есть класс:

Код: Выделить всё
tpolygon = class
    private
        fvertex     : tlist;
        fholes      : tlist;
        ffill_hash  : tlist;
        ....
end;                   


Элементами списка fvertex являются записи типа:

Код: Выделить всё
TPointF = record
        X : Real;
        Y : Real;
    end;         


Добавляю так:

Код: Выделить всё
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;                                     


Как всё таки правильно удалять объекты и освобождать память? :(
xterro
постоялец
 
Сообщения: 148
Зарегистрирован: 23.02.2014 13:49:33

Re: Как правильно освобождать память?

Сообщение kazalex » 30.08.2015 20:27:00

Код: Выделить всё
type PPointF = ^TPointF;
...
Dispose(PPointF(fvertex[i]));
kazalex
постоялец
 
Сообщения: 296
Зарегистрирован: 01.06.2012 14:54:10

Re: Как правильно освобождать память?

Сообщение Sharfik » 30.08.2015 20:35:14

Ты сам себя запутал, загнав все в одну строку.

Код: Выделить всё

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 написал.
Аватара пользователя
Sharfik
энтузиаст
 
Сообщения: 791
Зарегистрирован: 20.07.2013 01:04:30

Re: Как правильно освобождать память?

Сообщение xterro » 30.08.2015 21:46:54

Понял свою ошибку, спасибо ) Оказывается надо приводить не просто к типу PPointF, а к указателю на него. Я думал компилятор сам всё сделает как надо :)
Ещё такой вопрос, вот в данном случае, в списке я храню record и объекты(в двух других списках), для них в destroy() соотсвественно вызываю dispose(record) и free(для объектов).
А если бы у меня в списке хранились не записи, а простые числа, скажем типа real, мне всё равно для каждого элемента списка надо было бы вызывать dispose? или можно было бы вызвать просто для всего списка free(fvertex.free())?
xterro
постоялец
 
Сообщения: 148
Зарегистрирован: 23.02.2014 13:49:33

Re: Как правильно освобождать память?

Сообщение zub » 30.08.2015 22:00:44

Не используй TList для мелочи, используй простые массивы или какиенибудь generic надстройки над ними
zub
долгожитель
 
Сообщения: 2886
Зарегистрирован: 14.11.2005 23:51:26

Re: Как правильно освобождать память?

Сообщение xterro » 30.08.2015 22:07:31

zub писал(а):Не используй TList для мелочи, используй простые массивы или какиенибудь generic надстройки над ними

Я зараннее не знаю сколько точек или объектов у меня будет. Или делать каждый раз при добавлении записи в массив делать SetLength(arr, length(arr)+1) ? А это по феншую? :?
Ведь в массиве так же будут лежать указатели на объекты или на записи.

P.S. В деструкторе так же нужно будет пробегать по массиву и для каждого элемента вызывать free/dispose, или достаточно будет сделать что-то типа dispose(arr) и весь массив с содержимым почиститься?
xterro
постоялец
 
Сообщения: 148
Зарегистрирован: 23.02.2014 13:49:33

Re: Как правильно освобождать память?

Сообщение zub » 30.08.2015 22:21:12

>>SetLength(arr, length(arr)+1) ? А это по феншую?
если тебе надо добавить всего один элемент, то по феншую. Если ты так хочешь добавить 100500 элементов - то нет, по феншую будет SetLength(arr,сколько_надо) и потом работать с уже выделенными элементами

>>Ведь в массиве так же будут лежать указатели на объекты или на записи.
В массиве будет лежать то что тебе надо - хочешь сами данные, хочешь указатели. Естественно если ты хочешь сделать массив разнотипных элементов - придется делать на указателях, если однотипных то array of PointF - это массив элементов PointF, а не указателей на PointF

>>или достаточно будет сделать что-то типа dispose(arr) и весь массив с содержимым почиститься?
В простых случаях достаточно SetLength(arr, 0)
zub
долгожитель
 
Сообщения: 2886
Зарегистрирован: 14.11.2005 23:51:26

Re: Как правильно освобождать память?

Сообщение xterro » 30.08.2015 22:23:52

Теперь понятней стало, спасибо :)
xterro
постоялец
 
Сообщения: 148
Зарегистрирован: 23.02.2014 13:49:33

Re: Как правильно освобождать память?

Сообщение wavebvg » 31.08.2015 01:58:54

Sharfik писал(а):Использовать TList удобно, но он медленнее чем массивы.

Это как? Проверки на границы? Не пользуйтесь методами с проверкой границ. Больше тормозить нечему, а Capacity решит проблемы с тормозами при выделением памяти (в 90% случаев, если неизвестен размер списка в результате, это решает проблему с памятью).
wavebvg
постоялец
 
Сообщения: 354
Зарегистрирован: 28.02.2008 04:57:35

Re: Как правильно освобождать память?

Сообщение Sharfik » 31.08.2015 02:33:26

wavebvg писал(а):Это как?

Обход массива быстрее обхода класса на основе tlist и выше.
wavebvg писал(а):Проверки на границы?

Не знаком.
wavebvg писал(а):Capacity решит проблемы с тормозами при выделением памяти

Пробовал, разницы ноль было.
Аватара пользователя
Sharfik
энтузиаст
 
Сообщения: 791
Зарегистрирован: 20.07.2013 01:04:30

Re: Как правильно освобождать память?

Сообщение zub » 31.08.2015 02:52:26

>>Это как? Проверки на границы? Не пользуйтесь методами с проверкой границ. Больше тормозить нечему
Тормозить какраз есть чему, tlist это массив указателей на данные - лишние разименования указателей, лишние выделения памяти для элементов.
ИМХО за применение tlist как у ТС для простых структур данных надо двойки ставить))
zub
долгожитель
 
Сообщения: 2886
Зарегистрирован: 14.11.2005 23:51:26

Re: Как правильно освобождать память?

Сообщение xterro » 31.08.2015 08:55:00

Тут просто удобнее использовать списки. Можно конечно и массив взять, но получится разброд и шатание: один член класса - массив, второй, третий - список, как-то не айс имхо.
Я изначально не знаю сколько раз мне придётся вызывать
Код: Выделить всё
tpolygon.add_vertex(p : tpointf)

а ведь в случае массива, в каждом из этих вызовов пришлось бы делать setLength(), которая будет перевыделять память/копировать из старого массива(блока памяти) в новый, не нивелирует ли это, преимущество массивов перед списком? вроде как памяти занимать будет меньше, но и на производительность повлияет(операции перевыделения памяти).
Если бы я заранее знал сколько у меня будет точек, то да, без проблем, выделил нужное количество памяти и заполнил. Но не думаю что точек и полигонов будет настолько много, что придётся сильно оптимизировать :?
xterro
постоялец
 
Сообщения: 148
Зарегистрирован: 23.02.2014 13:49:33

Re: Как правильно освобождать память?

Сообщение Снег Север » 31.08.2015 09:57:20

xterro писал(а):а ведь в случае массива, в каждом из этих вызовов пришлось бы делать setLength()
увеличиваете массив не на один элемент, а на некоторую порцию, размер которой зависит от примерной оценки максимального размера массива и только при исчерпании свободного места
Аватара пользователя
Снег Север
долгожитель
 
Сообщения: 3038
Зарегистрирован: 27.11.2007 16:14:47

Re: Как правильно освобождать память?

Сообщение Kitayets » 31.08.2015 12:03:46

Если нотификация списка не требуется - эффективнее использовать TFPList (так в вики на сайте лазаруса написано).
Чтобы поменьше "кастов" было, если в списке одинаковые объекты - то дженериковую версию списка удобнее использовать TFPGList.

Динамические массивы - не особо быстрые. Выделения памяти - довольно долгие + после добавки размера (setLenght) runtime библиотека может переместить весь массив в другое место - с копированием всего содержимого. Кроме того, что это затратно по времени + все указатели на элементы массива становятся не валидными. Медленные проверки границ тоже. По этому всяких развесистых структур на дин. массивах лучше избегать ИМХО.

короче если нужен быстрый произвольны доступ к элементам, при этом с самой структурой данных ничего делать не надо (сортировка, произвольная вставка элементов с изм. размера) - используй массив (если заранее размер не известен, но в течении работы программы сильно/часто изменяться не будет - динамические), иначе - списки.
Kitayets
постоялец
 
Сообщения: 171
Зарегистрирован: 05.05.2010 21:15:24

Re: Как правильно освобождать память?

Сообщение Vadim » 31.08.2015 16:36:45

Kitayets писал(а):эффективнее использовать TFPList

У TList'а хранилище как раз и есть TFPList. ;-) Хотя, конечно, конструкция уже получается трёхэтажная. :-)
Vadim
долгожитель
 
Сообщения: 4112
Зарегистрирован: 05.10.2006 08:52:59
Откуда: Красноярск

След.

Вернуться в Общее

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 13

Рейтинг@Mail.ru