• dmk © (10.12.18 12:26) [0]
    Всем привет!
    Возможно ли сделать так, чтобы объект при уничтожении сам себе присваивал nil?
    Или надо FreeAndNil использовать?
  • dmk © (10.12.18 12:28) [1]
    Не туда запостил. Сорьки.
  • Плохиш © (10.12.18 13:07) [2]

    > чтобы объект при уничтожении сам себе присваивал nil?

    Прикольно, трупы сами себе могилу роют.
  • ухты © (10.12.18 13:16) [3]
    Как объект может себе нил присвоить? "Это же памятник" (с) ))
  • sniknik © (10.12.18 16:58) [4]
    должен быть специальный "зомби" агент, т.е. объект... он должен знать адрес своей переменной в единственном экземпляре, и перекрытый деструктор в котором он типа на последнем издыхании... оп и присваивает.

    > Или надо FreeAndNil использовать?
    это проще всего.
  • Mystic © (10.12.18 18:03) [5]
    А если у нас два указателя на один и тот же объект?
  • dmk © (10.12.18 19:18) [6]
    >А если у нас два указателя на один и тот же объект?
    У меня как раз такой случай. В одном объекты, а в другом ссылки на объекты.
    Я по ссылкам удаляю объекты.
  • dmk © (10.12.18 19:21) [7]
    Пока сделал удаление по ссылке:
    procedure FreeAndNil(AObj: PObject);
    begin
     if PObject(AObj)^ <> nil then
     begin
       PObject(AObj)^.Free;
       PObject(AObj)^ := nil;
     end;
    end;

    Но AutoNil конечно же предпочтительней.
    На мой взгляд такое возможно. Будем думать.
  • dmk © (10.12.18 19:26) [8]
    Короче надо свой ТОбжект писать. После FreeInstance это вполне возможно сделать, если есть внутренний массив со счетчиком и указателями ссылок.
  • ухты © (10.12.18 19:29) [9]

    > В одном объекты, а в другом ссылки на объекты.
    чудеса бывают
  • Sha © (10.12.18 20:33) [10]
    > ухты ©   (10.12.18 19:29) [9]

    иногда бывает полезно
  • ухты © (10.12.18 22:15) [11]
    полезно что? 2 списка? это совсем не америка
  • Sha © (10.12.18 22:29) [12]
    совсем америка случается совсем редко

    иногда бывает полезно работать с объектами через ссылки
  • ухты © (10.12.18 23:11) [13]
    а как без ссылок?
  • dmk © (10.12.18 23:27) [14]
    В общем сделал 2 варианта.
    1-й указываем адрес переменной объекта
    procedure TZObject.Free(AObj: PObject);
    begin
     inherited Free;
     PObject(AObj)^ := nil;
    end;

    а второй почти тоже самое.
    procedure FreeAndNil(AObj: PObject);
    begin
     if (AObj <> nil) then if (PObject(AObj)^ <> nil) then
     begin
       PObject(AObj)^.Free;
       PObject(AObj)^ := nil;
     end;
    end;

    Оба работают.
  • Sha © (10.12.18 23:29) [15]
    как обычно - доступ к данным через адрес данных

    а когда нужен дополнительный уровень косвенности,
    работают с данными через адрес адреса данных
  • ухты © (10.12.18 23:31) [16]
    Ну так при чем тут ссылки и работа с объектами ? )))
  • Sha © (10.12.18 23:50) [17]
    не видишь суслика? а он есть )
  • dmk © (11.12.18 00:43) [18]
    >Ну так при чем тут ссылки и работа с объектами ? )))
    Удобство управления для объектов созданных в разных местах.
    У вас просто такой случай не попался, а в сложных системах ссылки - это вообще норма.

     GenerateScene(1750, False, False); //<-Тут 1750 объектов добавилось

     LoadObj(GC_MODELSPATH + '...', RT, @ZCam, @gObject); //<- +1 объект
     LoadObj(GC_MODELSPATH + '...', RT, @ZCam, @gVarious); //<- +1 объект

     Init3DGrid(@gGrid, 33, 50, RT, @ZCam); //<- +1 объект
     
     //Ссылки на объекты
     Scene.AddObject(@gObject);
     Scene.AddObject(@gVarious);
     Scene.AddObject(@gGrid);

     // Работаем с объектами,
     // а потом бац и по ссылкам удаляем все объекты
     Scene.DestroyObjects;

     // nil - просто индикатор удаленности
  • dmk © (11.12.18 00:51) [19]
    Так это выглядит в коде. Просто и удобно.
    Особенно когда объектов тысячи. И все внешние переменные = nil.

    procedure TZObject.Free(AObj: PObject);
    begin
     inherited Free;
     PObject(AObj)^ := nil;
    end;

    procedure TZObjectsArray.DestroyObjects;
    var
     i: Integer;

    begin
     for i := Low(FObjects) to High(FObjects) do
     begin
       FObjects[i]^.Free(@FObjects[i]);
     end;

     SetLength(FObjects, 0);
     FNumObjects := 0;
    end;
  • dmk © (11.12.18 01:02) [20]
    У меня переменные многократно используются. То удаляются, то добавляются. Можно сильно запутаться, а так жесткая напоминалка об обнулении. И от класса объекта не зависит никак. И код сократился в разы - не надо помнить где и какой объект инициализирован.


     //Вариант 0 (Как было)
     gVariant.Free;
     gVariant := nil;
     gObject.Free;
     gObject := nil;
     gGrid.Free;
     gGrid := nil;

     //Вариант 1
     FreeAndNil(@gVarious);
     FreeAndNil(@gObject);
     FreeAndNil(@gGrid);

     //Вариант 2
     gVarious.Free(@gVarious);
     gObject.Free(@gObject);
     gGrid.Free(@gGrid);

     //Вариант 3 (самый удобный)
     Scene.DestroyObjects;
  • Германн © (11.12.18 02:47) [21]

    > dmk ©   (10.12.18 12:26)
    >
    > Всем привет!
    > Возможно ли сделать так, чтобы объект при уничтожении сам
    > себе присваивал nil?

    Никакой объект не имеет "объективной" возможности узнать сколько пользовательская программа сделала на него ссылок. Так что вопрос дурной.
    Вторая "дурность" вопроса заключается в самой "якобы" необходимости обниливать какую-то ссылку.
  • Германн © (11.12.18 02:49) [22]
    Это конечно ИМХО, но вполне обоснованное.
  • Sha © (11.12.18 09:24) [23]
    > Германн ©   (11.12.18 02:49) [22]

    чем-то это мне напоминает борьбу с GOTO )
  • KSergey © (11.12.18 11:26) [24]
    procedure TZObject.Free(AObj: PObject);

    А вот зачем указатель? TObject - уже указатель на объект же. Точно требуется еще и указатель на этот указатель?
  • KSergey © (11.12.18 11:27) [25]
    Если хочется переприсвоить значение самой переданнйо переменной - её просто надо передать по ссылке, т.е.

    procedure TZObject.Free(var AObj: TObject);

    Как-то оно прямее, понятнее, добрее
  • dmk © (11.12.18 11:49) [26]
    >А вот зачем указатель?
    У меня массив указателей на переменные, а не на адреса объектов.
    Инчае в параметрах придется писать обертку PObject(MyObjectType),
    а он не пропустит, т.к. строгая типизация, а указатели пропускает.
    Я уже все варианты перепробовал.
    Так проще всего:

    type
     PVar = ^TVar;
     TVar = Pointer;

    procedure TZObject.Free(AVar: TVar);
    begin
     inherited Free;

     //Очистка переменной
     if (AVar <> nil) then
       if (PVar(AVar)^ <> nil) then PVar(AVar)^ := nil;
    end;


    и вызов
    FObjects[i].Free(@FObjects[i]^);
    Все внешние переменные прилинкованные к массиву обнуляются и освобождаются.
  • dmk © (11.12.18 11:55) [27]
    Добавляем ссылку на переменную:
    Scene.AddObject(@gObject);
    Удаляем ссылку из массива указателей^
    FObjects[i].Free(@FObjects[i]^);
    Освобождаем объект и очищаем переменную:
    FreeAndNil(@gVarious);

    Очистка:
    procedure FreeAndNil(AVar: TVar);
    begin
     if (AVar <> nil) then if (PVar(AVar)^ <> nil) then
     begin
       PObject(AVar)^.Free;
       PVar(AVar)^ := nil;
     end;
    end;
  • dmk © (11.12.18 12:08) [28]
    У меня массив не
    FObjects: array of TZObject, а
    FObjects: array of PZObject;
    Ссылки на переменные и на другие массивы, которые уже TZObject.
  • KSergey © (11.12.18 12:35) [29]
    > dmk ©   (11.12.18 11:49) [26]
    > Все внешние переменные прилинкованные к массиву обнуляются и освобождаются.

    Чего??

    > dmk ©   (11.12.18 12:08) [28]
    > У меня массив не
    > FObjects: array of TZObject, а
    > FObjects: array of PZObject;

    Это понятно, про это и вопрос.

    > dmk ©   (11.12.18 12:08) [28]
    > Ссылки на переменные и на другие массивы, которые уже TZObject.

    Но зачем? вот что мне не понять.
    Обратите внимание: в VCL не смотря на то, что есть понятие "владелец объекта", который этот объект удаляет, кстати, совершенно успешно, и при всём при этом в VCL никаких PObject - нет совершенно. Ибо не нужны они. Правда-правда.
  • KSergey © (11.12.18 12:38) [30]
    > dmk ©   (11.12.18 11:55) [27]

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

    Это уже не говоря про то, что FreeAndNil() есть штатная же, и она иначе несколько устроена в смысле типов
  • dmk © (11.12.18 13:10) [31]
    >Если бы вы обрисовали задачу, которую всеми этими изворотами решаете -
    >уверен, вам бы подсказали более прямой и понятный путь решения задачи.
    В [18] описаны варианты создания объектов. Из файла [1], процедурная генерация [2], генерация массивов [3].
    Над объектами проводится куча действий:
    1. Трансформация
    2. Перекраска
    3. Текстурирование
    4. Слияние
    5. Отрисовка
    и т.д. и т.п.
    Действия в цикле однотипные, но доступ к объектам или через массив ссылок или через переменную. Нужно и так и так. Кол-во объектов может быть и сотни и тысячи и десятки тысяч. Переменных может быть также несколько десятков. Зачем мне листинги с удалением персональных переменных? Проще добавить в массив и потом махом все удалить. Поведение объектов хаотичное. Это 3D-сцена в общем. По ссылкам в массиве удобно все удалить или удалить выборочно.
  • KSergey © (11.12.18 14:58) [32]
    Из написанного вами вот что не понятно: зачем массив указателей на (сслыки) объекты?
    Да, я умышлено пишу "ссылки на объекты", ибо TObject - эти именно ссылка на объект по своей сути, ну или, более честно, указатель. Уже указатель!

    > Действия в цикле однотипные, но доступ к объектам или через массив ссылок или через переменную.

    Это вы так сделали, и это из кода видно.
    Но зачем? смысл какой всего этого? зачем вам ссылки непременно понадобилось в разных местах хранить?
    Кстати, почему бы не хранить целочисленные индексы в массиве объектов? зачем указатели?
    Индексы имеют тот плюс, что их можно контролировать. А указатели - нельзя, т.к. нет возможности достоверно узнать указывает указатель на валидное значение или на невалидное в памяти.
  • dmk © (11.12.18 15:01) [33]
    >Но зачем? смысл какой всего этого?
    Вот так это визуально выглядит:
    https://yadi.sk/i/tU7G3tfHrl4hBQ
    Сцена одна, а объекты из разных мест появляются.
  • KSergey © (11.12.18 16:03) [34]
    Не понятно (мне), но определённо красиво! )

    PS
    Расширение для файла .obj - режет глаз, конечно (ибо уже имеет своё устоявшееся значение в компьютерном мире). Но чем заменить - не знаю.
  • dmk © (11.12.18 16:15) [35]
    >.obj - режет глаз
    Зато бесплатно. Это открытый формат. Бесплатных очень мало.
  • ухты © (11.12.18 20:09) [36]

    > массив указателей на переменные
    еще чудесатее
    а вот этот новый фри скорее всего напрочь и эту переменную стирает, прям из кода))
  • FreeAndNil © (11.12.18 20:25) [37]
    По ссылкам в массиве удобно все удалить или удалить выборочно.

    а теперь я начинаю хотеть хранить ссылки на чудесный самоубивающийся класс в свойствах другого класса.

    привет, тебе, пернатый архитектор у которого не болит голова.
  • sniknik © (11.12.18 20:40) [38]
    > У меня массив указателей на переменные, а не на адреса объектов.
    повторю ранее говорившееся, читай внимательно - переменная объекта, это уже указатель.
    нет смысла в указателе на указатель, первый и так прекрасно на объект указывает, без дополнительных посредников.


    > Так проще всего:
    > type
    >   PVar = ^TVar;
    >   TVar = Pointer;
    >  
    > procedure TZObject.Free(AVar: TVar);
    > begin
    >   inherited Free;
    >  
    >   //Очистка переменной
    >   if (AVar <> nil) then
    >     if (PVar(AVar)^ <> nil) then PVar(AVar)^ := nil;
    > end;

    ... если нормально, то как мне кажется попроще, а делать будет то же самое.
    TObject вместо TVar чтобы, ты сам упоминал, без приведений типов, сойдет для всех потомков
    procedure TZObject.Free(var AVar: TObject);
    begin
      inherited Free;
      AVar:= nil;
    end;

  • Pavia © (11.12.18 20:52) [39]

    > Прикольно, трупы сами себе могилу роют.

    В нормальных языках это давно так реализовано.


    > Возможно ли сделать так, чтобы объект при уничтожении сам
    > себе присваивал nil?
    > Или надо FreeAndNil использовать?

    Нельзя.
    Embarcodere уже который год тянут кота за яйца, но автосборку мусора сделать не могут.
    Да проще свой препроцессор написать.
  • dmk © (11.12.18 20:54) [40]
    >sniknik ©   (11.12.18 20:40) [38]
    Так только для переменной подходит. Через PObject еще из массива освобождать можно.
    Где AVar - указатель на ячейку массива, а AVar^ доступ к переменной в ячейке, т.к. в ячейке хранится ссылка на другую переменную. Запутано конечно, но работает норм.
    В упрощенном виде:
    1. Доступ к переменной - PVar(AVar)^.
    2. Доступ к ячейке массива в которой хранятся ссылки на переменные - PObject(AVar^)^.
  • dmk © (11.12.18 20:56) [41]
    >Да проще свой препроцессор написать.
    Уже хочется свой компилятор если чесно. Куча ограничений кругом.
  • dmk © (11.12.18 20:57) [42]
    >Embarcodere уже который год тянут кота за яйца, но автосборку мусора сделать не могут.
    Они вам продадут эту фичу лет через 5 в версии 11.4. Это же маркетинг.
  • ухты © (11.12.18 22:38) [43]
    вы как переменные в ячйку запихали? ))
  • Тимохов Дима © (11.12.18 22:51) [44]
    мое имхо, что можно делать, что хочешь, лишь бы тебе было понятно и полезно.
    domain specific language, ёлки.
  • dmk © (11.12.18 23:04) [45]
    >вы как переменные в ячйку запихали? ))
    Для этого надо 2 высших иметь. У вас есть 2 высших?
  • ухты © (11.12.18 23:08) [46]
    тут 2 мало, тут надо щтук пять а лучше шесь, но у меня семь, так что все в порядке
  • dmk © (11.12.18 23:12) [47]
    >ухты
    А вообще вам сюда: http://butanti.forum24.ru/
    а здесь Обжект Паскаль обсуждают.
  • ухты © (11.12.18 23:18) [48]
    вы не обсуждаете а лепите. что то издалека напоминающее что то типа турбо паскаль ))
    со всвоими велосипедами в виде эти фри[энднил], ну и венцом из переменных в ячейках.
    и можно тольео повторить -

    > дичь какая-то
  • Германн © (12.12.18 02:03) [49]

    >  Sha ©   (11.12.18 09:24) [23]
    >
    > > Германн ©   (11.12.18 02:49) [22]
    >
    > чем-то это мне напоминает борьбу с GOTO )

    Почему только напоминает?
    Это та же самая борьба только на другом фронте. :)
  • Германн © (12.12.18 02:21) [50]

    > Sha ©   (11.12.18 09:24) [23]
    >
    > > Германн ©   (11.12.18 02:49) [22]
    >
    > чем-то это мне напоминает борьбу с GOTO )

    Ведь использование GOTO подразумевает использование Label, которые можно ставить в коде что в паскалевской, что в Дельфийской программе практически где угодно (возможно не везде, но я это не проверял).
    И IDE/Компилятор не могут уверенно указать на принципиальную ошибку алгоритма/программы.
    Т.о. вся ответственность за использование такого полностью ложится на его автора. Но готов ли автор её принять?
  • Sha © (12.12.18 10:02) [51]
    > Германн ©   (12.12.18 02:21) [50]

    И GOTO, и FreeAndNil обычно не требуются программисту.

    Но в тех редких случаях, когда их применение действительно имеет смысл,
    они способны существенно упростить алгоритм или повысить скорость.
  • sniknik © (12.12.18 11:41) [52]
    >>sniknik ©   (11.12.18 20:40) [38]
    > Так только для переменной подходит. Через PObject еще из массива освобождать можно.
    да, я понял, у тебя в объекте указатель на себя же, на внешнюю переменную с собой(которая тоже указатель). по нему "обниляеш" именно внешнюю.
    поначалу сбило то, что ты в примере его во Free переменной передаешь, а не берешь из внутренних переменных.

    вообще, "претензия" к такому подходу только в том что это громоздко и сложно для понимания (самому через пару лет поменять понадобится...).

    лучше бы как то поменять логику, обойтись например без внешней вообще, работать со спискам объектов, в котором их уничтожение уже реализовано (приснопамятный сборщик мусора... ), ну вот, тут адрес внешний внутрь передается, но смысла в этом не вижу, если уж нужна для работы используй и бросай без Free, список потом сам позаботится.
    type
     TMyObject = class(TObject)
       Obj: TMyObject;
       destructor Destroy; override;
     end;

    destructor TMyObject.Destroy;
    begin
     inherited;
     Form1.Edit1.Text:= '!!!!!!'
    end;

    procedure TForm1.Button1Click(Sender: TObject);
    var
     i: integer;
     ObL: TObjectList;
     pO: TMyObject;
    begin
     ObL:= TObjectList.Create;
     try
       ObL.Add(TObjectList.Create);
       ObL.Add(TObject.Create);
       i := ObL.Add(TMyObject.Create);
       pO:= TMyObject(ObL.Items[i]);
       pO.Obj:= @pO;
     finally
       ObL.Free;
     end;
    end;

  • dmk © (12.12.18 12:07) [53]
    >вообще, "претензия" к такому подходу только в том
    >что это громоздко и сложно для понимания
    Так я без наставлений в народ вышел. Просто спросил, а меня уже запинали.
    У меня 3D-эшечка. 3D-объекты вещь комплексная и создаются у меня в разных местах и разными методами. Модифицируются также в разных местах и даже в разных модулях. Загружаются в массивы или переменные. Вот например, система частиц - это же массив созданных процедурно или загруженных из файла объектов. У них даже классы обработки разные. Только общий предок TZObject. Частицы находятся в одном массиве. Объекты взаимодействия в другом или вообще в отдельной переменной. У меня и так перерасход памяти жуткий идет, а вы мне предлагаете еще один массив с T-классом сделать. Двойное существование объекта в общем то не нужно. Поэтому я и придумал массив ссылок (сцена). Может как то иначе этот массив можно представить?

    У меня так сделано:
    type
     PZScene = ^TZScene;
     TZScene = class
     private
       FObjects: array of PZObject;
       FNumObjects: Integer;
       FSceneStatistic: TSceneStatistic;
       procedure SetObject(Index: Integer; Value: PZObject); inline;
       function GetObject(Index: Integer): PZObject; inline;
     public
       constructor Create;
       destructor Destroy; override;
       procedure AddObject(Value: PZObject);
       procedure ChangeTarget(ATarget: PBitmap64);
       procedure DeleteObject(Value: PZObject);
       procedure DestroyObjects;
       procedure DrawObjects;
       function GetMaxObjectsDepth: Single;
       function GetDepth: Single;
       procedure InverseDraw;
       function LowIndex: Integer; inline;
       function HighIndex: Integer; inline;
       function NumJoins: Integer;
       function NumPoints: Integer;
       function NumTriangles: Integer;
       function ObjectExist(Value: PZObject): Boolean; inline;
       function ObjectIndex(Value: PZObject): Integer; inline;
       procedure Reset;
       procedure SetFill(Value: Boolean);
       procedure SetStroke(Value: Boolean);
       procedure SetOpacity(Value: Single);
       procedure ScaleObject(Value: PZObject; F: Single);
       procedure ScaleObjects(Value: Single);
       procedure SetCheckerColors(Args: array of TColor32);
       procedure SetHSVColors(AOrient: TPlaneType);
       procedure SetObjectFirst(Value: PZObject);
       procedure SetRandomColors;
       procedure UpdateStatistic;
       //---
       property Objects[Index: Integer]: PZObject read GetObject write SetObject;
       property NumObjects: Integer read FNumObjects;
       property Statistic: TSceneStatistic read FSceneStatistic;
     end;

    procedure TZScene.AddObject(Value: PZObject);
    begin
     if (Value^ <> nil) then
     begin
       if not ObjectExist(Value) then
       begin
         Inc(FNumObjects);
         SetLength(FObjects, FNumObjects);
         FObjects[High(FObjects)] := Value;
       end;
     end;
    end;

    procedure TZScene.DeleteObject(Value: PZObject);
    var
     i, k: Integer;
     Found: Boolean;

    begin
     if (FNumObjects > 0) and (Value <> nil) then
     begin
       Found := False;
       k := LowIndex;

       for i := LowIndex to HighIndex do
       begin
         if FObjects[i] = Value then
         begin
           FreeAndNil(@Value^);
           Found := True;
           Continue;
         end
         else //Пропустим удаленный объект
         begin
           FObjects[k] := FObjects[i];
           Inc(k);
         end;
       end;//for

       FNumObjects := k;
       SetLength(FObjects, FNumObjects);

       //Если не найден, то удаляем объект вне сцены
       if (not Found) then FreeAndNil(@Value^);
     end;
    end;

    procedure TZScene.DestroyObjects;
    var
     i: Integer;

    begin
     if (FNumObjects > 0) then
     begin
       for i := Low(FObjects) to High(FObjects) do
       begin
         FObjects[i].Free(@FObjects[i]^);
       end;

       SetLength(FObjects, 0);
       FNumObjects := 0;
     end;
    end;


    Добавляются объекты в сцену так:
     //Удаляем старый объект
     Scene.DeleteObject(@gObject);

     //Создаем и загружаем файл
     LoadObj(OpenMeshDialog.FileName, RT, @ZCam, @gObject);

     if gObject.Correct then
     begin
       Scene.AddObject(@gObject);
       Scene.SetObjectFirst(@gObject);
     end;


    Потом сцена удаляется:
    procedure TRenderForm.FreeScene;
    begin
     if bSceneActive then
     begin
       //Массив ссылок на Z-Объекты
       Scene.DestroyObjects;

       //Объекты вне массива
       FreeAndNil(@gVarious);
       FreeAndNil(@gObject);
       FreeAndNil(@gGrid);
       FreeAndNil(@gFrustum);

       //Кнопка загрузки
       FLoadBtn.Visible := False;
       FLoadBtn.Enable := False;

       //Флаг использования 3D
       bSceneActive := false;
     end;
    end;

    Но мой вариант рабочий и вроде уже привык.
    Можно как то проще сделать? Буду рад услышать хорошие советы.
  • dmk © (12.12.18 12:15) [54]
    Мне nil понадобился, чтобы точно узнавать — инициализирован объект или нет.
    Если nil - то создаем в этой переменной или ячейке в массиве. У меня объекты динамически создаются/удаляются и какая переменная освободится заранее не известно.
    Вот здесь видно поведение объектов:
    https://yadi.sk/i/tU7G3tfHrl4hBQ
  • sniknik © (12.12.18 16:13) [55]
    > Можно как то проще сделать?
    имхо конечно, но я как раз проще и посоветовал, работать со списком, стандартным. а не с массивом, и своим "велосипедом" по его обработке...
    ну, совсем без велосипеда не обойтись, но вот наследуй твой TZScene от TObjectList и у тебя сразу появятся стандартные методы по добавлению/удалению объектов, и "дестроить" их самому/следить за этим/за массивом не нужно будет, и т.д. много преимуществ/упрощений на мой взгляд.
    не, я конечно не совсем в теме, что у тебя там, со стороны не видно, вот к примеру зачем в 2-х местах ссылки? бери всегда из списка да и все. копию просто игнорь, в следующий раз если понадобится снова из списка, а nil-ов в нем попросту не будет, - стал не нужен объект, удалил из списка, а он уже сам его освободит... удобно.
  • dmk © (12.12.18 17:10) [56]
    >TObjectList
    Тут есть оговорка. VCL не используется. Почти чистый WinApi. Вплоть до своего менеджера памяти.
  • Владислав © (12.12.18 19:50) [57]
    Какой феерический трындец.

    > TObjectList
    > Тут есть оговорка. VCL не используется.

    Можно посмотреть, как он реализован, не слишком сложная задача.

    После просмотра этого:

    >type
    >  PZScene = ^TZScene;
    >  TZScene = class

    и этого:

    >Вплоть до своего менеджера памяти.

    у меня когнитивный диссонанс возникает.

    Не дай бог такое приснится.
  • virex(home) © (12.12.18 20:24) [58]
    > pavia ©   (11.12.18 20:52) [39]
    >
    >
    > > прикольно, трупы сами себе могилу роют.
    >
    > в нормальных языках это давно так реализовано.
    >
    >
    > > возможно ли сделать так, чтобы объект при уничтожении сам
    > > себе присваивал nil?
    > > или надо freeandnil использовать?
    >
    > нельзя.
    > embarcodere уже который год тянут кота за яйца, но автосборку мусора сделать не могут.
    > да проще свой препроцессор написать.
    нормальный язык это где gc находит трупы и закапывает?
  • Германн © (13.12.18 01:59) [59]

    > Sha ©   (12.12.18 10:02) [51]
    >
    > > Германн ©   (12.12.18 02:21) [50]
    >
    > И GOTO, и FreeAndNil обычно не требуются программисту.
    >
    > Но в тех редких случаях, когда их применение действительно
    > имеет смысл,
    > они способны существенно упростить алгоритм или повысить
    > скорость.

    Вот с этим я как раз и не спорил. Более того. У меня был случай, когда GOTO давал гораздо более понятный при просмотре/анализе/отладке код.
    А вот FreeAndNil никогда. Возможно потому, что у меня не достаточно было опыта.
  • Германн © (13.12.18 02:12) [60]

    > Sha ©   (12.12.18 10:02) [51]
    >
    > > Германн ©   (12.12.18 02:21) [50]
    >
    > И GOTO, и FreeAndNil обычно не требуются программисту.
    >
    > Но в тех редких случаях, когда их применение действительно
    > имеет смысл,
    > они способны существенно упростить алгоритм или повысить
    > скорость.

    Не в службу, а в дружбу. А не затруднит-ли вас, Александр
    написать простой рабочий пример, где применение FreeAndNil хоть чем-то оправдано?
  • sniknik © (13.12.18 10:19) [61]
    > где применение FreeAndNil хоть чем-то оправдано?
    часто использую для редко используемых форм, т.е. вот есть форма в проге которая используется редко, и после использования надолго не нужна, логично ее создавать перед использованием, и уничтожать после. nil в ее переменной это как индикатор, что нужно ее создать перед показом, что не висит она в данный момент в "фоне".
    конечно можно было бы ввести какой другой индикатор, но это было бы как то нелогично.
  • sniknik © (13.12.18 10:21) [62]
    +
    я выше не про саму функцию FreeAndNil, а про принцип, "занилять" формы проще просто присваиванием в деструкторе.
  • Leonid Troyanovsky © (13.12.18 10:39) [63]

    > sniknik ©   (13.12.18 10:19) [61]

    >  что нужно ее создать перед показом, что не висит она в
    > данный момент в "фоне".

    Валидность ссылки легко проверяется по Screen.Forms.

    FAN - MD ;)

    --
    Regards, LVT.
  • Sha © (13.12.18 10:50) [64]
    > Германн ©   (13.12.18 02:12) [60]

    Обычно это массивы, списки, пулы, очереди и т.п. объектов, из которых долго или неудобно исключать адреса по одному, а гораздо удобнее обнилить или каким-то образом пометить адрес данных. А впоследствии перепаковать или освободить целиком весь контейнер.

    В качестве второго примера - многоэтажные этажерки из вложенных try.
  • sniknik © (13.12.18 16:35) [65]
    > Валидность ссылки легко проверяется по Screen.Forms.
    перебором массива сравнивая с несуществующей переменной формы, или по отсутствию текста с именем формы в существующих? вместо простого сравнения if ххх <> nil ...
    не не думаю, что это легко. оно конечно все относительно, и для "бешеной собаки 10 верст не крюк", но вот не хочется менять 2 строки кода, на ... да хотя бы на 3, хотя их явно будет побольше.
  • Eraser © (13.12.18 20:38) [66]
    FreeAndNil оправдан в FMX, чтобы код вел себя одинаково и в VCL, но это скорее редкость.
    FreeAndNil скорее подходит для отладки.


    > Embarcodere уже который год тянут кота за яйца, но автосборку
    > мусора сделать не могут.

    они ее уже успели сделать и уже успели передумать http://blog.marcocantu.com/blog/2018-october-Delphi-ARC-directions.html
  • Германн © (14.12.18 01:50) [67]

    > Sha ©   (13.12.18 10:50) [64]
    >
    > > Германн ©   (13.12.18 02:12) [60]
    >
    > Обычно это массивы, списки, пулы, очереди и т.п. объектов

    Примерно так я и думал. Задач, в которых нужны "массивы, списки, пулы, очереди и т.п. объектов у меня лично не было.

    > sniknik ©   (13.12.18 16:35) [65]
    >
    > > Валидность ссылки легко проверяется по Screen.Forms.
    > перебором массива сравнивая с несуществующей переменной
    > формы
    А почему бы и нет? Ну не миллионы же у вас в списке Forms!
  • Leonid Troyanovsky © (14.12.18 09:39) [68]

    > sniknik ©   (13.12.18 16:35) [65]

    > не не думаю, что это легко.

    Ну, считай, что оно уже есть.

    function AssignedFormVar(fv: TForm): Boolean;
    var
     i: Longint;
    begin
     Result := Assigned(fv);
     if Result then
       with Screen do
         for i := 0 to Screen.FormCount-1 do
           begin
             Result := (fv = Forms[i]);
             if Result then
               Break;
           end;
    end;

    --
    Regards, LVT.
  • sniknik © (14.12.18 10:14) [69]
    > А почему бы и нет?
    а смысл? менять простое сравнение целочисленной переменной на цикл? ...
    > Ну не миллионы же у вас в списке Forms!
    а вот это тут совсем не причем.

    > Ну, считай, что оно уже есть.
    круто.. весь проникся мудростью... сарказм.
    но в общем то функция ниуть не лечит ту болезнь от которой спасает/ремендуют использовать FreeAndNil.
    в итоге тот же вопрос - а смысл?
    procedure TForm1.Button2Click(Sender: TObject);
    var
     form: TForm;

     function AssignedFormVar(fv: TForm): Boolean;
     var
       i: Longint;
     begin
       Result := Assigned(fv);
       if Result then
         with Screen do
           for i := 0 to Screen.FormCount-1 do
             begin
               Result := (fv = Forms[i]);
               if Result then
                 Break;
             end;
     end;

    begin
     form:= TForm.Create(self);
     try
       //test - error
       if AssignedFormVar(form)
         then Edit1.Text:= 'Assigned'
         else Edit1.Text:= 'not Assigned';

       form.Free; //FreeAndNil(form);
       if AssignedFormVar(form)
         then Edit2.Text:= 'Assigned'
         else Edit2.Text:= 'not Assigned';
     finally
       form.Free;
     end;
    end;
  • Leonid Troyanovsky © (14.12.18 10:42) [70]

    > sniknik ©   (14.12.18 10:14) [69]

    > но в общем то функция ниуть не лечит ту болезнь от которой
    > спасает/ремендуют использовать FreeAndNil.

    Не совсем понял пример, но, видимо, д.б.

     finally
       if AssignedFormVar(form) then
         form.Free;
     end;

    --
    Regards, LVT.
  • sniknik © (14.12.18 15:55) [71]
    > Не совсем понял пример
    одно из того почему рекомендуют FreeAndNil вместо Free, как раз такая ситуация, не нужно доп.проверок. а тут от чего уходим к тому и пришли, только из-за желания использовать "крутой" метод проверки.
  • dmk © (14.12.18 22:03) [72]
    >только из-за желания использовать "крутой" метод проверки
    Но ведь других средств нет. Только проверка на nil.
    После FreeInstance образуется адресное пространство, которое может быть в зоне AV.
    Неудобная недоработка.
  • sniknik © (14.12.18 23:31) [73]
    > Но ведь других средств нет. Только проверка на nil.
    она есть во Free которым уже все надрессированы пользоваться, "на автомате". осталось "передрессироваться" на использование FreeAndNil, и проблема "уйдет".
    пример вон выше, скопируй получи ошибку, а после раскоментарь/замени Free на FreeAndNil.

    > Неудобная недоработка.
    эта, даже не знаю что сказать... вот прямо перед вами доработанное средство... или как говорил классик "разруха она в головах".
  • Leonid Troyanovsky © (16.12.18 09:22) [74]

    > sniknik ©   (14.12.18 15:55) [71]

    > одно из того почему рекомендуют FreeAndNil вместо Free

    FAN - MD. Костыль при кривом проектировании.

    Особенно для форм, кои есть компоненты и, в случае удержания ссылок на оные,
    должно пользовать механизм Notification.
    Ну, или, на худой конец, массивом Forms, для отыскания утерянной формы.

    Бо, и глобальные переменные - MD.

    --
    Regards, LVT.
  • sniknik © (16.12.18 15:28) [75]
    > FAN - MD. Костыль при кривом проектировании.
    и че ты не консультант борланда был когда он и функцию безопасного обниления делал да проверку на нил во фри сувал, чуть ли не изначально при появлении генофонда... уж объяснил бы им ужо.

    > должно пользовать механизм Notification.
    ага, особенно когда из потока к форме обращаешься т.е. нотификейшн перед нотификейшном, первый проверка есть ли она (только куда что посылать) второе собственно рабочее событие... ну очень удобно.

    > Бо, и глобальные переменные - MD.
    вообще чего мелочится? программирование - MD. (аппликатион если чё тоже глобальная переменная)

    з.ы. весь пост - сарказм. уже почему то по другому не получается. ведь все просто - есть возможность у языка, пользуйся, если к месту, удобно, нет "скрытых багов". нет же куча народу с догмами, того нельзя сего нельзя, и хоть бы что аргументированно... но нет, за аргументы выдают что-то по заковыристые, скоро 2 + 2 будут советовать не просто операцию использовать а что-то через COM-обьекты, микросервисы и т.д. еже с ними.
  • ухты © (16.12.18 19:57) [76]
    Фри реально костыль. )
  • sniknik © (16.12.18 23:47) [77]
    и давно ты кошерный деструктор использовал? который не костыль.
    а вот была бы ява там подобное синтаксическим сахаром называют, ... а баги фичами...
  • ухты © (17.12.18 00:20) [78]
    Ну нет, синтаксический сахар это другое. Например тернарная операция или типа того.
    Кстати, буквально вот http://pda.delphimaster.net/?id=1542948910&n=3, в делфи ввели возможность объявление переменной "по месту" + определение типа в компайл тайм, вот это тоже сахар. А фри это немного из другой оперы. И как на мой взгляд, особо ничего не давшая. АВ происходит ничуть не реже. ))

    А что касается механизм Notification для вашей формы, то я согласен с вами, оно тут никчему. Вместо класической глобальной переменной, сделал бы статичное свойство в классе самой формы, и все довольны.))
  • Eraser © (17.12.18 03:50) [79]

    > ухты ©   (17.12.18 00:20) [78]


    > АВ происходит ничуть не реже. ))

    счастье, когда оно происходит, а не молча портит память.
  • sniknik © (17.12.18 10:26) [80]
    > сделал бы статичное свойство в классе самой формы,
    кто то умный давно сказал - "не плодите сущности"

    > и все довольны.))
    у меня нет цели сделать всех довольными... работа другая.
  • ухты © (17.12.18 10:41) [81]
    Где вы тут сущность увидели? тут как бы наоборот, инкапсуляция - привет ооп, нет гл. переменных - привет LVT и нет доп. нотификашн и т.п. - вам привет, итого все довольны.

    > счастье, когда оно происходит, а не молча портит память.
    так а отчего тогда спасали отцы? )) в том то и дело имеем тоже и костыль
  • sniknik © (17.12.18 12:09) [82]
    > Где вы тут сущность увидели?
    переменная в переменной это не сущность? лишняя.

    она сама по себе показатель, нет смысла относится к переменной по другому только из-за того что там форма... а если нет? если указатель, простой объект, интерфейс... и что каждый по своему, как то по особому проверять? (согласен если есть объективные причины, но их нет!)

    xml разбирал? мелкософтским iдомдокументом. там на отсутствующие ноды nil возвращает вместо обьекта... и никого не парит, что единственный способ проверить что вернулось, это сравнить с nil. почему с формами должно быть по другому? с чего им такая честь?
    и тут кстати мысль образовалась... у вас извиняюсь за личностные вопросы сколько типов ложек для супа? ну в смысле одна для борща, другая для рассольника третья для ухи и тд...? ;) т.к. если вы их не градуируете по содержимому, то советовать раздельное для каждого типа объектов сравнение попросту не имеете морального права...  это батюшка называется лицемерием.
  • ухты © (17.12.18 12:30) [83]
    Вы мкня пугаете, в какой переменной? ))
  • имя (17.12.18 12:43) [84]
    Удалено модератором
  • sniknik © (17.12.18 14:41) [85]
    > в какой переменной? ))
    из примера выше, например во в этой
    > procedure TForm1.Button2Click(Sender: TObject);
    > var
    >   form: TForm;
    form - переменная, ты предлагаешь статику в описании типа, т.е. TForm - в итоге получается переменная в переменной, или если буквально с доступом "через переменную-тип".  в общем излишние сложности, т.к. она сама показатель, ничего более не нужно.
  • Германн © (18.12.18 02:10) [86]

    > Eraser ©   (17.12.18 03:50) [79]
    >
    >
    > > ухты ©   (17.12.18 00:20) [78]
    >
    >
    > > АВ происходит ничуть не реже. ))
    >
    > счастье, когда оно происходит, а не молча портит память.
    >

    Вот истинно 100500 да ещё и плюс. И вот очень многие "нетроешники" почему-то до сих пор этой простой истины не понимают!
  • Leonid Troyanovsky © (18.12.18 10:50) [87]

    > sniknik ©   (17.12.18 14:41) [85]

    > > в какой переменной? ))
    > из примера выше, например во в этой

    Поле, дельфийское поле.

    Вот, кстати, простой пример для формы должной жить в одном экз.
    http://delphimaster.net/view/2-1177420765/57

    Громоздко, да. Но такой уж он феньшуй.

    --
    Regards, LVT.
  • sniknik © (18.12.18 11:59) [88]
    > Но такой уж он феньшуй.
    https://ru.wikipedia.org/wiki/Фэншуй
    Нет каких-либо научных доказательств того, что мистические требования фэншуй реальны; научное сообщество относит фэншуй к лженауке.

    что в общем то подтверждается по ссылке.
    http://delphimaster.net/view/2-1177420765/57
    procedure TForm1.Notification;
    begin
    inherited;
    if AComponent = FForm2 then
      if Operation = opRemove then
        FForm2 := nil;
    end;

    оппа... а с чем же это ты тогда "борешься"? под "капотом" то то же самое... все так же опираешься на обниление переменной формы.

    просто принцип в действии - "никогда не делать банальным и простым то, что можно сделать сложным и прекрасным..."
    все ясно.
  • Leonid Troyanovsky © (18.12.18 12:07) [89]

    > sniknik ©   (18.12.18 11:59) [88]

    > procedure TForm1.Notification;
    > begin
    > inherited;
    > if AComponent = FForm2 then
    >   if Operation = opRemove then
    >     FForm2 := nil;
    > end;
    > оппа... а с чем же это ты тогда "борешься"? под "капотом"
    > то то же самое... все так же опираешься на обниление переменной
    > формы.

    Поле. Его зовут полем.
    А опираемся на Notification.

    Жаль, что ты не захотел понять.

    --
    Regards, LVT.
  • sniknik © (18.12.18 14:10) [90]
    > Поле. Его зовут полем.
    это переменная, что определенная в форме, что локально в процедуре (как у меня в примере выше) что глобально. плевать. поле чисто формальное название для переменных в форме. использовать только "поля" - ограничивать себя же. что делать в моем, что выше примере? или когда нет главной формы в которой делать  "поле" (или их описано несколько, в зависимости от каких то критериев выбирается на старте одно)? сложность "нотификации" возрастет многократно.

    или для разных случаев у вас тоже разные варианты сравнений? ... а у вас сколько типов ложек для супов?

    > Жаль, что ты не захотел понять.
    понимание это обоюдный процесс, когда "в одну сторону" это навязывание своего мнения оппоненту. о чем вас кстати никто не просил.
  • ухты © (18.12.18 17:00) [91]
    ооп зло
  • Leonid Troyanovsky © (19.12.18 10:20) [92]

    > sniknik ©   (18.12.18 14:10) [90]

    > навязывание своего мнения оппоненту. о чем вас кстати никто
    > не просил.

    Ну, извини меня, Коля.

    --
    Regards, LVT.
  • Leonid Troyanovsky © (07.01.19 15:18) [93]

    > Leonid Troyanovsky ©   (18.12.18 10:50) [87]

    > Громоздко, да. Но такой уж он феньшуй.

    Вот юнит, призванный упростить дело:

    unit AutoNil;

    interface

    uses
     classes, Forms;

    type
     PComponent = ^TComponent;

     TMApplication = class(TApplication)
     private
       FCompVars: TList;
     protected
       procedure Notification(AComponent: TComponent; Operation: TOperation); override;
       procedure AutoNilVarRegister(anv: PComponent); virtual;
     end;

    procedure NilAfterDestroy (pc: PComponent);

    implementation

    procedure NilAfterDestroy;
    begin
     TMApplication(Application).AutoNilVarRegister(pc);
    end;

    procedure TMApplication.Notification;
    var
     i: Longint;
    begin
     inherited;
     if (Operation = opRemove) then
       for i := FCompVars.Count-1 downto 0  do
         if (PComponent(FCompVars[i])^ = AComponent) then
           begin
             PComponent(FCompVars[i])^ := nil;
             RemoveFreeNotification(AComponent);
             FCompVars.Delete(i);
           end;
    end;

    procedure TMApplication.AutoNilVarRegister;
    begin
     if not Assigned(FCompVars) then
       FCompVars := TList.Create;
     FreeNotification(anv^);
     FCompVars.Add(anv);
    end;

    initialization
     Application.Free;
     Application := TMApplication.Create(nil);

    end.

    А вот пример использования:

    type
     TForm1 = class(TForm)
       Button1: TButton;
       Button2: TButton;
       procedure Button1Click(Sender: TObject);
       procedure Button2Click(Sender: TObject);
     private
       { Private declarations }
       f2, f3: TForm;
     public
       { Public declarations }
     end;

    var
     Form1: TForm1;

    implementation

    {$R *.dfm}

    uses
     AutoNil;

    type
     TForm2 = class(TForm)
       procedure DoClose(var Action: TCloseAction); override;
     end;

    procedure TForm2.DoClose;
    begin
     inherited;
     Action := caFree;
    end;

    procedure TForm1.Button1Click(Sender: TObject);
    begin
     if not Assigned(f2) then
       begin
         f2 := TForm2.CreateNew(nil);
         f3 := f2;
         NilAfterDestroy(@f2); // теперь после разрушения формы ссылка обнилится
         NilAfterDestroy(@f3);
       end;
    end;

    procedure TForm1.Button2Click(Sender: TObject);
    begin
     if Assigned(f2) then
       f2.Show;
    end;

    --
    Regards, LVT.
  • Leonid Troyanovsky © (07.01.19 15:30) [94]

    > Leonid Troyanovsky ©   (07.01.19 15:18) [93]

    Решил сэкономить на конструкторе и попал на грабли.
    Создавать список  нужно в initialization (ну, или, дейс-но, в конструкторе).
    Т.е.

    procedure TMApplication.AutoNilVarRegister;
    begin
     FreeNotification(anv^);
     FCompVars.Add(anv);
    end;

    initialization
     Application.Free;
     Application := TMApplication.Create(nil);
     TMApplication(Application).FCompVars := TList.Create;

    end.

    --
    Regards, LVT.
Есть новые Нет новых   [118686   +15][b:0.001][p:0.003]