На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
! ПРАВИЛА РАЗДЕЛА · FAQ раздела Delphi · Книги по Delphi
Пожалуйста, выделяйте текст программы тегом [сode=pas] ... [/сode]. Для этого используйте кнопку [code=pas] в форме ответа или комбобокс, если нужно вставить код на языке, отличном от Дельфи/Паскаля.
Следующие вопросы задаются очень часто, подробно разобраны в FAQ и, поэтому, будут безжалостно удаляться:
1. Преобразовать переменную типа String в тип PChar (PAnsiChar)
2. Как "свернуть" программу в трей.
3. Как "скрыться" от Ctrl + Alt + Del (заблокировать их и т.п.)
4. Как прочитать список файлов, поддиректорий в директории?
5. Как запустить программу/файл?
... (продолжение следует) ...

Вопросы, подробно описанные во встроенной справочной системе Delphi, не несут полезной тематической нагрузки, поэтому будут удаляться.
Запрещается создавать темы с просьбой выполнить какую-то работу за автора темы. Форум является средством общения и общего поиска решения. Вашу работу за Вас никто выполнять не будет.


Внимание
Попытки открытия обсуждений реализации вредоносного ПО, включая различные интерпретации спам-ботов, наказывается предупреждением на 30 дней.
Повторная попытка - 60 дней. Последующие попытки бан.
Мат в разделе - бан на три месяца...
Модераторы: jack128, D[u]fa, Shaggy, Rouse_
  
> Работа с TObjectList , Не освобождается память при удалении элемента-объекта из переменной типа TObjectList
    Детский вопрос: имеется объект - наследник TObject
    ExpandedWrap disabled
          TMap = class
           public
            Name: string;
            GeodeticLimits: TLimits;   //геодезические координаты в радианах
            PlaneLimits: TLimits;      //прямоугольные координаты
            NumberOfObjects: integer;  //количество объектов карты
            Units: byte;               //единицы измерения
            ListOfObjects: TObjectList;      //список объектов карты
            ErrorMsg: string;          //строка диагностики
            Loaded: boolean;           //загружена или нет
            constructor Create;
          end;

    набор карт хранится в глобальной переменной BigMap, которая имеет класс TObjectList
    var
    BigMap: TObjectList;

    при создании OwnsObjects указывается как True

    ExpandedWrap disabled
        if BigMap = nil then
                 begin
                    BigMap:= TObjectList.Create(True);
                    BigMap.Add(Map);
                 end
                 else BigMap.Add(Map);


    при необходимости удаления
    ExpandedWrap disabled
      var OnThere, Find: boolean;
          CurrentMap: TMap;
      .............
      begin
      ..................
          I:= 0;
          Find:= False;
              //проверка на попадание точки ВС в карту из списка загруженных
              repeat
                 CurrentMap:= TMap(BigMap.Items[I]) ;
                 OnThere:= IamThere(MyPlace, CurrentMap.PlaneLimits);
                 if IamThere(MyPlace, CurrentMap.PlaneLimits)=False then
                  begin
                     BigMap.Delete(I);  //удаляем, раз ВС не на карте
                     BigMap.Pack;       //упаковка
                     BigMap.Capacity:= BigMap.Count; //выравнивание по реальному счетчику
                     Find:= True;
                  end
                  else
                  inc(I);
              until (Find = True) or (I = BigMap.Count);
      .........
      end;

    все делает, но память не освобождает. В чем может быть проблема?
      >все делает, но память не освобождает.

      Деструктор TMap вызывается?
      Перекрытия Destroy я не вижу, а кто будет ListOfObjects оcвобождать?
      Сообщение отредактировано: MBo -
        А разве он не вызывается автоматически?
          Вызывается деструктор TObject, который освобождает память, записанную в InstanceSize, финализирует динамические поля. Но про внутренние объекты он ничего не знает.

          Нужно объявить и реализовать перекрытый (override) деструктор, в котором освободить то, что создавал вручную (и не забыть inherited)
            Ок, добавил destructor TMap.Destroy; override;
            ExpandedWrap disabled
              destructor TMap.Destroy;
              begin
                 GeodeticLimits.Free;
                 PlaneLimits.Free;
                 ListOfObjects.Clear;
                 ListOfObjects.Free;
                 inherited Destroy;
              end;

            Но результат тот же.
              Деструктор вызывается? Проверено?

              В чём выражается "но память не освобождает"?

              ListOfObjects освобождает свои объекты?

              В общем, тут много неясного, без телепатии тяжко.
              Сообщение отредактировано: MBo -
                Смотрю в отладчике - ничего не понятно: после удаления (Bimap.Delete(I)) ListOfObjects пустой, но указатель есть, его TList не nil, но пустой. В диспетчере задач видно, что сколько занято памяти, столько и осталось занятым после удаления...
                  > ListOfObjects пустой, но указатель есть
                  А он и не должен обнуляться.
                  Есть процедура FreeAndNil, которой пользуются при необходимости иметь нулевую ссылку после уничтожения (замечу, что на объект может быть несколько ссылок, а обнулится только одна)

                  Диспетчер задач - не всегда показатель.
                    Цитата MBo @

                    > ListOfObjects пустой, но указатель есть
                    Диспетчер задач - не всегда показатель.

                    А как еще отслеживать память?
                    Из-за утечек получаю outofmemory, причем, довольно скоро, потому что загружаемые и не удаленные карты по 100-200 Мб.
                    По идее, даже если создается простейший наследник TObject, его деструктор надо перекрывать для корректного освобождения ресурсов. И далее по иерархии своих классов. Я правильно понимаю?
                      >А как еще отслеживать память?

                      Включить ReportMemoryLeaksOnShutdown

                      http://www.gunsmoker.ru/2009/05/blog-post_24.html

                      >По идее, даже если создается простейший наследник TObject, его деструктор надо перекрывать для корректного освобождения ресурсов.

                      Если есть внутренние объекты, созданные в твоём коде - да, иначе нет.
                      О статических полях и данных с автоматическим управлением (строки, динамические массивы, если они не содержат объекты) заботиться не нужно.
                        Спасибо, постараюсь разобраться
                          Цитата mnj @
                          все делает, но память не освобождает. В чем может быть проблема?

                          У тебя код удаления карт в #1 какой-то странный - он удаляет из списка не все карты, на которые не попадает заданная точка, а только одну, первую попавшуюся (выход из цикла по первому Find = true)

                          Цитата mnj @
                          По идее, даже если создается простейший наследник TObject, его деструктор надо перекрывать для корректного освобождения ресурсов.

                          В деструкторе нужно удалять\освобождать объекты (экземпляры классов), а также динамические структуры данных (указатели), выделенные функциями New, GetMem, AllocMem, ReallocMem (или функциями WinApi). Как уже было сказано, автоматически очищаются только строки, динамические массивы (не содержащие объектов и указателей), варианты и интерфейсы.

                          Цитата mnj @
                          постараюсь разобраться

                          В первую очередь обрати внимание на класс объекта карты (то, что хранится в ListOfObjects), поскольку эти объекты, по идее, и занимают основной объем карты в 100-200 Мб, о которых ты говоришь. Поэтому, если деструктор этого объекта что-то не удаляет, то отсюда и возникает большая утечка памяти.

                          Цитата mnj @
                          А как еще отслеживать память?

                          Кроме ReportMemoryLeaksOnShutdown можно проверить освобождение памяти в конкретных местах вставкой вызовов функций GetMemoryManagerState или GetHeapStatus (она хоть и deprecated, но проще в использовании, чем GetMemoryManagerState).
                            Прежде всего - спасибо за внимание к моей проблеме. Теперь по порядку:
                            Цитата leo @
                            У тебя код удаления карт в #1 какой-то странный - он удаляет из списка не все карты, на которые не попадает заданная точка, а только одну, первую попавшуюся (выход из цикла по первому Find = true)

                            Все карты и не грузятся. Грузятся только те карты, на которые попадает точка в стартовой позиции, их м.б. 1, 2 или 3 штуки (я брал готовые, а они внахлест сделаны, с перекрытием друг друга, не как нормальные планшеты), поэтому по мере продвижения точка может покинуть только 1 карту.
                            Про деструктор:
                            Вот у меня создан простейший класс, от которого ползет все:
                            ExpandedWrap disabled
                                  TMyPoint = class
                                    Lon: real;   //долгота
                                    Lat: real;   //широта
                                    //destructor Destroy; override;
                                  end;

                            Нужен ли ему свой конструктор и свой деструктор, если он прямой наследник TObject и отличается только наличием двух статических полей? В отладчике видно, что он создается без собственного конструктора и без проблем со всеми своими полями, а вот удалить его с деструктором или без него не получается, в отладчике он по-прежнему жив-здоров, если удалять экземпляр проcтым Free, а не FreeAndNil. Получается, что деструктор ему не нужен вовсе.
                            ExpandedWrap disabled
                              destructor TMyPoint.Destroy;
                              begin
                                inherited Destroy;
                              end;

                            Что еще можно написать для него, если деструктор у предка - пустой.

                            А вот его родственник:
                            ExpandedWrap disabled
                                //треугольник
                                TTriangle = class
                                  Vertexes: array [0..2] of TMyPoint;
                                  constructor Create;
                                  destructor Destroy; override;
                                end;
                              ....
                              constructor TTriangle.Create;
                              var I: integer;
                              begin
                                  for I := 0 to 2 do
                                  Self.Vertexes[I]:= TMyPoint.Create;
                              end;
                              destructor TTriangle.Destroy;
                              var I: integer;
                              begin
                                   for I := 0 to 2 do
                                   begin
                                      if Assigned (Self.Vertexes[I]) then Self.Vertexes[I].Free;
                                   end;
                                   inherited;
                              end;

                            Тем не менее
                            FastMM4 выдает такую штуку:
                            5CE4D6 [Types_classes.pas][Types_classes][TTriangle.$bctr$qqrv][389]
                            5D0B78 [main.pas][main][Triangulation$qqrp20System.Classes.TList][590]
                            5D0CF7 [main.pas][main][CreatePlane$qqrv][634]
                            5D11D1 [main.pas][main][TGLForm.FormCreate$qqrp14System.TObject][773]
                            The block is currently used for an object of class: TTriangle
                            От конструктора формы к процедуре рисования контура самолета (CreatePlane), потом к триангуляции и к треугольнику. Строка проблемного элемента - конструктор этого самого треугольника.
                            Или
                            5CDC92 [Types_classes.pas][Types_classes][TLimits.$bctr$qqrv][212]
                            5CE258 [Types_classes.pas][Types_classes][TMyFrame.$bctr$qqrv][349]
                            5D399A [main.pas][main][TGLForm.BuildFrames$qqrv][1466]
                            5D11EF [main.pas][main][TGLForm.FormCreate$qqrp14System.TObject][776]
                            The block is currently used for an object of class: TMyPoint
                            Тут все упирается в TLimits (габаритный контейнер карты), который тоже несложный, вроде и создается и умирает корректно, а TMyPoint, получается, палки в колеса ставит все равно, коли без freeandnil не обойтись:
                            ExpandedWrap disabled
                                  TLimits = class  //границы листа карты
                                    SW: TMyPoint;  //юго-западный угол
                                    NW: TMyPoint;  //северо-западный
                                    SE: TMyPoint;  //юго-восточный
                                    NE: TMyPoint;  //северо-восточный
                                    CoordSys: boolean;
                                    constructor Create;
                                    destructor Destroy; override;
                                  end;
                              ................
                              constructor TLimits.Create;
                              begin
                               // inherited Create;
                                SW:= TMyPoint.Create; //юго-запад
                                NW:= TMyPoint.Create; //северо-запад
                                SE:= TMyPoint.Create; //юго-восток
                                NE:= TMyPoint.Create; //северо-восток
                                CoordSys:= True;      //по умолчанию - прямоугольные координаты
                              end;
                               
                              destructor TLimits.Destroy;
                              begin
                                if Assigned(SW) then FreeAndNil(SW);
                                if Assigned(NW) then FreeAndNil(NW);
                                if Assigned(SE) then FreeAndNil(SE);
                                if Assigned(NE) then FreeAndNil(NE);
                                inherited;
                              end;


                            Где правда, если с TLimits есть проблема и в чем?
                            ПС - огромная утечка в функции тесселяции полигона при построении объекта карты, который отправляется в ListOfObjects, но это видно только в логе, FastMM говорит Unknown
                              > в отладчике он по-прежнему жив-здоров, если удалять экземпляр проcтым Free, а не FreeAndNil.

                              Что значит - жив-здоров? Указатель без обнуления указывает всё туда же, но его участок памяти помечен как свободный, очищать его ни к чему.

                              >Получается, что деструктор ему не нужен вовсе.

                              Такому классу переписывать деструктор не нужно, как я уже говорил. Более того, и класс здесь не нужен, если не предусматривается наследование-расширение, так как никакой функциональности или инкапсуляции он не реализует. Просто массив или запись.

                              > if Assigned (Self.Vertexes[I]) then Self.Vertexes[I].Free;

                              Проверка здесь ни к чему. Free само разберётся, нулевой указатель освобождать не станет
                              Сообщение отредактировано: MBo -
                                Цитата MBo @
                                Что значит - жив-здоров? Указатель без обнуления указывает всё туда же, но его участок памяти помечен как свободный, очищать его ни к чему.

                                Жив-здоров - это после выполнения Free можно по-прежнему присвоить значение полю объекта как вполне существующему, значит он продолжает жить и память не освобождает. Но мне нужно убить его совсем. Класс для точки - конечно, жирно. Это я от лени. Правильно было бы
                                ExpandedWrap disabled
                                    PPointRecord = ^TPointRecord;          //точка
                                    TPointRecord = record
                                      Lat: real;
                                      Lon: real;
                                    end;
                                  >Но мне нужно убить его совсем

                                  Видимо, у тебя в голове сложилась не вполне верная картина работы с памяться, и ты исходишь из неверных предпосылок.

                                  Вот менеджер памяти сдавал комнату Васе, потом Вася выехал, а комната всё существует, и даже мебель стоит по-старому. Если спросить, сколько кастрюль на верхней полке, ответ будет тоже, что и при Васе.
                                  Но она вакантна, и когда-либо может быть снова сдана - Пете, который уже и мебель переставит, и кастрюли свалит в духовку.
                                    Цитата MBo @
                                    Видимо, у тебя в голове сложилась не вполне верная картина работы с памяться, и ты исходишь из неверных предпосылок.

                                    Вот менеджер памяти сдавал комнату Васе, потом Вася выехал, а комната всё существует, и даже мебель стоит по-старому. Если спросить, сколько кастрюль на верхней полке, ответ будет тоже, что и при Васе.
                                    Но она вакантна, и когда-либо может быть снова сдана - Пете, который уже и мебель переставит, и кастрюли свалит в духовку.

                                    Вполне возможно. Я полагал, что менеджер памяти, имея поляну (память), для Васи оградил кусочек на ней. Вася уехал, менеджер ограду снял, теперь туда может поселиться Петя, которому может понадобиться кусочек побольше или поменьше и оградку надо ставить соответствующую, иначе Коля может попасть на Петину жилплощадь. А так получается, что удаленный методом Free экземпляр Вася (например, класса который представляет точку) делает свободным (вакантным) свой кусочек памяти и, хотя отладчик по-прежнему показывает последние значения Васиных полей и с ними можно производить манипуляции, любой Коля может придти на это место по усмотрению менеджера памяти и в отладчике для экземпляра Вася рано или поздно будут выводится любые, даже абсурдные значения, в то время как переменная Коля в отладчике будет показывать адекватные значения, если я правильно понял. Как мне убедиться, что память, которую занимал Вася, действительно вакантна?
                                    Сообщение отредактировано: mnj -
                                      Цитата
                                      А так получается, что удаленный методом Free экземпляр Вася (например, класса который представляет точку) делает свободным (вакантным) свой кусочек памяти и, хотя отладчик по-прежнему показывает последние значения Васиных полей и с ними можно производить манипуляции, любой Коля может придти на это место по усмотрению менеджера памяти и в отладчике для экземпляра Вася рано или поздно будут выводится любые, даже абсурдные значения, в то время как переменная Коля в отладчике будет показывать адекватные значения, если я правильно понял


                                      Всё верно

                                      >Как мне убедиться, что память, которую занимал Вася, действительно вакантна?

                                      Пройти отладчиком по шагам вызов Free с включенными Use Debug DCUs и убедиться, что деструктор срабатывает. Если утечка и есть, то она вызвана другими причинами
                                        Цитата mnj @
                                        Как мне убедиться, что память, которую занимал Вася, действительно вакантна?

                                        Полноценный FastMM + опции FullDebugMode, CheckHeapForCorruption. Заполняют освобожденные участки шаблоном $80808080. Либо в деструкторе занулять занимаемое объектом место
                                          Спасибо всем за ценные советы. Но в процессе решения этой задачи (точнее, отработки одного из дырявых мест) вот такая есть утечка. Полноценный FastMM говорит, что она в процедуре триангуляции:
                                          5CB160 [Unit1.pas][Unit1][TfrmGL.Triangulation$qqrv][156]
                                          Вот объявлены типы (избавились от классов, делаем рекордами)
                                          ExpandedWrap disabled
                                              //точка
                                              Point = ^P;
                                              P = record
                                                X: glFloat;
                                                Y: glFloat;
                                              end;
                                              //треугольник
                                              PTr = ^T;
                                              T = record
                                                Vertexes: array[0..2] of P;
                                              end;

                                          Переменные:
                                          ExpandedWrap disabled
                                              Points, Triangles: TList;

                                          Вот триангуляция:
                                          ExpandedWrap disabled
                                            procedure TfrmGL.Triangulation;
                                            var I: integer;
                                                Tr: PTr;     //треугольник
                                                R: real;   //векторное произведение
                                                B: boolean;
                                                PP: Point;     //точка (вершина)
                                            begin
                                               Triangles:= TList.Create;  //список треугольников
                                               I:= 0;
                                               while Points.Count > 3 do
                                               begin
                                                 if I+2 = Points.Count then I:= 0;//если конец списка, то начинаем сначала
                                                 New(Tr);       //пустой треугольник
                                                 PP:= Points.Items[I];
                                                 Tr.Vertexes[0]:= PP^; //первая вершина
                                                 PP:= Points.Items[I+1];
                                                 Tr.Vertexes[1]:= PP^;//вторая вершина
                                                 PP:= Points.Items[I+2];
                                                 Tr.Vertexes[2]:= PP^;//третья вершина
                                                 R:= VectorMultiply(Tr.Vertexes[0],Tr.Vertexes[1],Tr.Vertexes[2]);
                                                 B:= IsPIn_Vector(Tr.Vertexes[0],Tr.Vertexes[1],Tr.Vertexes[2],Points);
                                                 //если R(векторное произведение AB и AC) < 0 - левая тройка векторов и
                                                 //остальные точки не попадают в текущий треугольник, то
                                                 if (R < 0) and (B = False)then
                                                 begin
                                                      Triangles.Add(Tr);//добавляем треугольник в список треугольников
                                                      Dispose(Point(Points.Items[I+1]));
                                                      Points.Delete(I+1); //удаляем вторую (в треугольнике) вершину из списка,
                                                      //остальные автоматом сдвигаются вперед к первой
                                                 end
                                                 else  //иначе проверяем следущий набор из трех вершин
                                                 if I+2 < Points.Count-1 then inc(I)   //если не конец списка минус 2 точки
                                                 else                                  //переходим на 1 точку дальше
                                                 if I+2 = Points.Count-1 then I:= 0; //если стоим за 2 точки до конца списка
                                               end;                                   //идем сначала
                                            end
                                          ;
                                          Удаление:
                                          ExpandedWrap disabled
                                            procedure TfrmGL.FormDestroy(Sender: TObject);
                                            var I: integer;
                                             
                                            begin
                                                wglMakeCurrent (0, 0);
                                                wglDeleteContext(hrc);
                                                for I := 0 to Triangles.Count-1 do
                                                  Dispose(PTr(Triangles.Items[I]));
                                                Triangles.Free;
                                                for I := 0 to Points.Count-1 do
                                                  Dispose(Point(Points.Items[I]));
                                                Points.Free;
                                            end;

                                          Вроде все удаляется, но в репорте 5 штук неопознанных (понятно, что из триангуляции). Где ошибка, не могу найти. Полный код в аттаче.


                                          Прикреплённый файлПрикреплённый файлTriangles.rar (55,74 Кбайт, скачиваний: 76)
                                            New(Tr); выполняется на каждом шаге, а занесение созданного треугольника в список - не на каждом.
                                            Занесенные освобождаются, а незанесенные - остаются висеть.
                                              Цитата MBo @
                                              New(Tr); выполняется на каждом шаге, а занесение созданного треугольника в список - не на каждом.
                                              Занесенные освобождаются, а незанесенные - остаются висеть.

                                              Спасибо! Сам бы не додумался о таких простых вещах
                                              ExpandedWrap disabled
                                                     if (R < 0) and (B = False)then
                                                     begin
                                                          Triangles.Add(Tr);//добавляем треугольник в список треугольников
                                                          Dispose(Point(Points.Items[I+1]));
                                                          Points.Delete(I+1); //удаляем вторую (в треугольнике) вершину из списка,
                                                          //остальные автоматом сдвигаются вперед к первой
                                                     end
                                                     else  //иначе проверяем следующий набор из трех вершин
                                                     begin
                                                      if   I+2 < Points.Count-1 then inc(I)   //если не конец списка минус 2 точки
                                                      else                                  //переходим на 1 точку дальше
                                                      if I+2 = Points.Count-1 then I:= 0;  //если стоим за 2 точки до конца списка
                                                      Dispose(Tr);                  //убираем лишний треугольник и идем сначала
                                                     end;
                                                mnj
                                                Зачем раньше времени создавать Tr, если в функции VectorMultiply и IsPIn_Vector можно передать непосредственно точки из Points?
                                                К тому же записи (record) давно поддерживают методы, в т.ч. и конструкторы (а для старых версий типа D7 можно вместо record использовать тип object).
                                                ExpandedWrap disabled
                                                  type
                                                    //треугольник
                                                    PTr = ^T;
                                                    T = record
                                                      Vertexes: array[0..2] of P;
                                                      constructor Init(const P1,P2,P3: P);
                                                    end;
                                                  constructor PTr.Init(const P1,P2,P3: P);
                                                  begin
                                                    Vertexes[0]:=P1;
                                                    Vertexes[1]:=P2;
                                                    Vertexes[2]:=P3;
                                                  end;
                                                   
                                                  procedure TfrmGL.Triangulation;
                                                  var
                                                    ...
                                                    Tr: PTr;     //треугольник
                                                    P1,P2,P3: Point;  //точка (вершина)
                                                  begin
                                                    ...
                                                       P1:= Points.Items[I];
                                                       P2:= Points.Items[I+1];
                                                       P3:= Points.Items[I+2];
                                                       R:= VectorMultiply(P1^,P2^,P3^);
                                                       B:= IsPIn_Vector(P1^,P2^,P3^,Points);
                                                       if (R < 0) and (B = False)then
                                                       begin
                                                         New(Tr, Init(P1^,P2^,P3^));  //создаем треугольник и инициализируем его вызовом конструктора
                                                         Triangles.Add(Tr);  //добавляем треугольник в список треугольников
                                                         ...


                                                PS: Названиям типов лучше давать нормальные осмысленные имена, начинающиеся с T..., а не просто P и T как у тебя.
                                                  leo
                                                  Цитата leo @
                                                  Зачем раньше времени создавать Tr, если в функции VectorMultiply и IsPIn_Vector можно передать непосредственно точки из Points?

                                                  Да, верно. Тогда не будет нужды удалять ненужные треугольники, так как они не будут создаваться. Насчет конструкторов в записях я просто как-то не думал, пользуя от лени класс от tobject. Но если мне, допустим, нужно соорудить габаритный контейнер для листа карты, то удобнее делать класс (я так думаю):
                                                  ExpandedWrap disabled
                                                    PMyPoint = ^TMyPoint;
                                                    TMyPoint = record
                                                      Longitude: real;
                                                      Latitude: real;
                                                     constructor Init(const X,Y: real);
                                                    end;
                                                     
                                                    constructor TMyPoint.Init(const X, Y: real);
                                                    begin
                                                      Longitude:= X;
                                                      Latitude:= Y;
                                                    end;
                                                     //а в контейнере угловые точки
                                                    TBorders = class
                                                      SW: PMyPoint;
                                                      NW: PMyPoint;
                                                      NE: PMyPoint;
                                                      SE: PMyPoint;
                                                     constructor Create;
                                                     destructor Destroy; override;

                                                  end;
                                                    Цитата mnj @
                                                    Но если мне, допустим, нужно соорудить габаритный контейнер для листа карты, то удобнее делать класс (я так думаю):

                                                    А я так не думаю, поскольку TBorders - это фиксированная структура из 4-х точек, которые не имеет смысла выделять динамически по отдельности. Лучше заменить PMyPoint на TMyPoint, тогда и необходимость в деструкторе отпадет (и соотв-но в использовании класса). По моему для габаритной рамки удобнее использовать вариантную запись типа:
                                                    ExpandedWrap disabled
                                                      PMapFrame = ^TMapFrame;
                                                      TMapFrame = array[0..3] of TMyPoint;
                                                       
                                                      PBorders = ^TBorders;
                                                      TBorders = record
                                                      case integer of
                                                      0: (Frame: TMapFrame);         //точки в виде массива
                                                      1: (SW, NW, NE, SE: TMyPoint); //отдельные точки с осмыслеными названиями
                                                      end;

                                                    В эту запись можно добавить конструктор(ы) для инициализации, а также некоторые методы, например, функцию определения попадания точки в габариты (типа PointInFrame).
                                                    Сообщение отредактировано: leo -
                                                      Цитата mnj @
                                                      Points, Triangles: TList;

                                                      В данном случае использовать стандартный TList неудобно, т.к. приходится писать кучу лишнего кода для удаления\освобождения его элементов. Лучше его переопределить, чтобы память под удаляемые элементы освобождалась автоматически. Для этого достаточно переопределить метод TList.Notify
                                                      ExpandedWrap disabled
                                                        TFreeMemList = class(TList)
                                                        protected
                                                          procedure Notify(Ptr: Pointer; Action: TListNotification); override;
                                                        end;
                                                         
                                                        procedure TFreeMemList.Notify(Ptr: Pointer; Action: TListNotification);
                                                        begin
                                                          if (Ptr <> nil) and (Action = lnDeleted) then
                                                            FreeMem(Ptr);
                                                        end;
                                                      Такой список можно использовать для любых простых записей, не требующих финализации (т.е. не содержащих строк и т.п.), когда для освобождения элемента можно использовать FreeMem вместо Dispose (=Finalize+FreeMem)
                                                        Вообще, получается, что в моем случае классы, как строительный материал, не нужны, все можно сконструировать записями, тот же объект на карте:
                                                        ExpandedWrap disabled
                                                              TMapObject = record      //объект на карте
                                                               Order: byte;           //байт для сортировки при записи, означает порядок рисования
                                                               Class_code: integer;   //код классификатора объекта
                                                               Key: integer;          //уникальный номер объекта
                                                               Local: byte;  //код локализации - линейный, площадной, точечный и т.п.
                                                               Borders: TBorders;  //габаритный контейнер
                                                               NumberOfSubs: integer; //число подобъектов
                                                               NumberOfPoints: integer; //количество точек
                                                               NumberOfSem: integer;    //количество семантических данных
                                                               CoordList: array of TMyPoint; //список координат
                                                               SubObj: array of TMapObject;             //список подобъектов
                                                               Name: ANSIstring;         //название или подпись (если есть)
                                                               Semantic: integer;        //семантический ключ для рисования/нерисования
                                                               Visibility: boolean;      //true- рисуется в любом масштабе, false - проверяется на размер
                                                               constructor Create(AVisibility: boolean);
                                                              end;

                                                        Цитата leo @
                                                        Такой список можно использовать для любых простых записей, не требующих финализации (т.е. не содержащих строк и т.п.), когда для освобождения элемента можно использовать FreeMem вместо Dispose (=Finalize+FreeMem)

                                                        А как очистить TList, заполненный такими TMapObject?
                                                          Цитата mnj @
                                                          Вообще, получается, что в моем случае классы, как строительный материал, не нужны, все можно сконструировать записями, тот же объект на карте:

                                                          Не нужно впадать в крайности. Не имеет смысла создавать классы для простых\примитивных структур типа точек, треугольников, габаритов и т.п. А TMapObject - довольно навороченная структура, которая к тому же может иметь (а может и не иметь) подобъекты SubObj аналогичной структуры, которые имеет смысл создавать динамически. Поэтому, на мой взгляд, лучше объявить TMapObject как класс, заменить тип SubObj на TObjectList и удалять его в деструкторе.

                                                          Цитата mnj @
                                                          А как очистить TList, заполненный такими TMapObject?

                                                          Если записи не простые (содержат строки, динамические массивы и т.п.), то удалять их нужно через Dispose(Тип_указателя_записи(Ptr));
                                                            Цитата leo @
                                                            Не нужно впадать в крайности. Не имеет смысла создавать классы для простых\примитивных структур типа точек, треугольников, габаритов и т.п.

                                                            Стараюсь :) . Но в тех же габаритах есть необходимость учитывать формат координат (градусы или метры) и производить манипуляции в зависимости от текущего формата. Получается, что нужен все-таки класс, чтобы воспользоваться полиморфизмом и определить метод TBorders.DoSomething для градусной нотации и для метрической.
                                                              Цитата mnj @
                                                              Но в тех же габаритах есть необходимость учитывать формат координат (градусы или метры) и производить манипуляции в зависимости от текущего формата. Получается, что нужен все-таки класс...

                                                              Не знаю. Всё таки TBorders - это не самостоятельная сущность, а просто свойство\характеристика объекта карты или карты в целом. Поэтому учет "DoSomething для градусной нотации и для метрической" может делаться в этих объектах, а не в самом TBorders. Всё зависит от конкретики (в частности от того, что действительно скрывается за DoSomething), иначе можно опять "впасть в крайность" и прийти к выводу, что точка и треугольник тоже должны быть классами, т.к. они также должны учитывать "градусную и метрическую нотацию".
                                                                Цитата leo @
                                                                Всё зависит от конкретики (в частности от того, что действительно скрывается за DoSomething), иначе можно опять "впасть в крайность" и прийти к выводу, что точка и треугольник тоже должны быть классами,

                                                                Пожалуй, остается только согласиться
                                                                  Еще раз спасибо всем за помощь и ценные советы. :)
                                                                  1 пользователей читают эту тему (1 гостей и 0 скрытых пользователей)
                                                                  0 пользователей:


                                                                  Рейтинг@Mail.ru
                                                                  [ Script execution time: 0,0788 ]   [ 17 queries used ]   [ Generated: 18.09.25, 15:23 GMT ]