Мастера DELPHI, Delphi programming community Рейтинг@Mail.ru Титульная страница Поиск, карта сайта Написать письмо 
| Новости |
Новости сайта
Поиск |
Поиск по лучшим сайтам о Delphi
FAQ |
Огромная база часто задаваемых вопросов и, конечно же, ответы к ним ;)
Статьи |
Подборка статей на самые разные темы. Все о DELPHI
Книги |
Новинки книжного рынка
Новости VCL
Обзор свежих компонент со всего мира, по-русски!
|
| Форумы
Здесь вы можете задать свой вопрос и наверняка получите ответ
| ЧАТ |
Место для общения :)
Орешник
Коллекция курьезных вопросов из форумов
Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / rsdn.org

 
Чтобы не потерять эту дискуссию, сделайте закладку « предыдущая ветвь | форум | следующая ветвь »

FreeAndNil


dmk ©   (10.12.18 12:26

Всем привет!
Возможно ли сделать так, чтобы объект при уничтожении сам себе присваивал 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://delphimaster.ru/cgi-bin/forum.pl?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.


версия для печати

Написать ответ

Ваше имя (регистрация  E-mail 







Разрешается использование тегов форматирования текста:
<b>жирный</b> <i>наклонный</i> <u>подчеркнутый</u>,
а для выделения текста программ, используйте <code> ... </code>
и не забывайте закрывать теги! </b></i></u></code> :)


Наверх

  Рейтинг@Mail.ru     Титульная страница Поиск, карта сайта Написать письмо