Как определить действителен ли указатель?
От: defrag  
Дата: 12.09.03 07:58
Оценка:
День добрый, господа коллеги.

Такая у меня проблема...
Динамически создаю объект, допустим форму
Form2:=TForm2.Create(nil)

Затем, при обработке события от кнопки на этой форме я ее уничтожаю методом Free.
TForm2.Button1Click(Sender:TObject)
begin
Free;
end;

Но при этом, указатель Form2 продолжает оставаться инициализированным.
Вопрос такой, как определить, уничтожен ли объект на который указывает Form2?
Вопрос касается не только форм, но и любых наследников TObject иже с ними.

Заренее спасибо
Re: Как определить действителен ли указатель?
От: EqWu Россия  
Дата: 12.09.03 08:02
Оценка: -2
Здравствуйте, defrag, Вы писали:

D>Вопрос такой, как определить, уничтожен ли объект на который указывает Form2?


IsBadWritePtr или IsBadReadPtr
Re[2]: Как определить действителен ли указатель?
От: defrag  
Дата: 12.09.03 08:23
Оценка:
Спасибо, идея была не плохая, но к сожалению,
обе фунции выдаютт FALSE даже после уничтожения объекта
Re: Как определить действителен ли указатель?
От: Leonid Troyanovsky  
Дата: 12.09.03 09:19
Оценка:
Здравствуйте, defrag, Вы писали:

D>Вопрос такой, как определить, уничтожен ли объект на который указывает Form2?

D>Вопрос касается не только форм, но и любых наследников TObject иже с ними.

Вообще-то, глобальная переменная Form2 must die

Для форм есть список форм:

for i:= Screen.FormCount-1 do
if (Screen.Forms[i] is TFormX) and (..) then

Для контролов есть Parent.Controls

Для компонентов есть Owner.Components или FreeNotification.

--
С уважением, LVT.
--
С уважением, LVT
Re: Как определить действителен ли указатель?
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 12.09.03 10:02
Оценка: -1
Здравствуйте, defrag, Вы писали:

D>День добрый, господа коллеги.


D>Такая у меня проблема...

D>Динамически создаю объект, допустим форму

D>Form2:=TForm2.Create(nil)


D>Затем, при обработке события от кнопки на этой форме я ее уничтожаю методом Free.


D>TForm2.Button1Click(Sender:TObject)

D>begin
D>Free;
D>end;

D>Но при этом, указатель Form2 продолжает оставаться инициализированным.

D>Вопрос такой, как определить, уничтожен ли объект на который указывает Form2?
D>Вопрос касается не только форм, но и любых наследников TObject иже с ними.

D>Заренее спасибо


Это проблема менеджера памяти, т.к. память не уничтожается а добавляется в выделенную но неиспользуемую для повторного использования. Физическое удаление происходит только при размере непрерывной неиспользуемой памяти больше 16 кб и выравненной по 16 кб.
Выход может быть найден при передаче в объект ссылки переменной ссылающейся на объект в список объекта и при Destroy обнулять, но при этом при выходе этой переменной из видимости нужно ее из этого списка удалять.

Обычно для форм заранее известна переменная ссылпющуюся на создаyyый объект и делают так
TForm2.Destroy;
Begin
Form2:=nil;
Inherrited;
end;
и солнце б утром не вставало, когда бы не было меня
Re[2]: Как определить действителен ли указатель?
От: Leonid Troyanovsky  
Дата: 12.09.03 10:24
Оценка:
Здравствуйте, Serginio1, Вы писали:

S> Обычно для форм заранее известна переменная ссылпющуюся на создаyyый объект и делают так

S> TForm2.Destroy;
S> Begin
S> Form2:=nil;
S> Inherrited;
S> end;

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

Да и, вообще, плодить глобальные переменные — грех.

--
С уважением, LVT.
--
С уважением, LVT
Re[3]: Как определить действителен ли указатель?
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 12.09.03 10:49
Оценка: -1
Здравствуйте, Leonid Troyanovsky, Вы писали:

LT>Здравствуйте, Serginio1, Вы писали:


S>> Обычно для форм заранее известна переменная ссылпющуюся на создаyyый объект и делают так

S>> TForm2.Destroy;
S>> Begin
S>> Form2:=nil;
S>> Inherrited;
S>> end;

LT> Так делать нельзя (никогда).

LT> TForm2 — класс, экземпляров у него может быть сколько хочешь(хоть два).

LT> Да и, вообще, плодить глобальные переменные — грех.


LT>--

LT>С уважением, LVT.
Ну ты и выдернул кусок. Выше описывалось как лучше это делать, но при создании формы все равно создается глобальная переменная и почему бы ее не использовать??? Это один из выходов. Кроме всего прочего до вормы можно добраться и через ee Owner
и солнце б утром не вставало, когда бы не было меня
Re: Как определить действителен ли указатель?
От: akasoft Россия  
Дата: 12.09.03 10:50
Оценка:
Здравствуйте, defrag, Вы писали:

D>Такая у меня проблема...

D>Динамически создаю объект, допустим форму
D>...

Вообще-то, то, что написано, выглядит несколько бредово. Потому как, если надо закрыть форму по событию — нажатию кнопки, то надо вызвать метод Close, а если надо ещё и освободить указатель, то есть как минимум два способа.

Первый

procedure TForm1.Button1Click(Sender: TObject);
begin
    Form2 := TForm2.Create(nil);
    with Form2 do
    begin
        // Делаем с ней, что надо. Обычно надо ShowModal.
        
        Free; // Освобождаем, но после работы с формой.
    end;
end;


Второй

procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction);
begin
    // Готовимся к закрытию
    // а затем
    Form2 := nil;
    Action := caFree;
end;


D>Вопрос такой, как определить, уничтожен ли объект на который указывает Form2?

D>Вопрос касается не только форм, но и любых наследников TObject иже с ними.

Обычно делается проверка на равенство nil, например

if Assigned(Obj) then
begin
    Obj.Free;
    Obj := nil;
end;
... << RSDN@Home 1.1 beta 2 >>
Re: Как определить действителен ли указатель?
От: defrag  
Дата: 12.09.03 11:02
Оценка:
Господа, прошу прощение за то что выбрал не очень удобный пример с формами.
Он действительно был притяну за уши.
Попробую объяснить понагляднее.
Итак:

Var a,b:TObject;
begin
a:=TObject.Create(nil);
b:=a;
b.Free;



после таких манипуляций a все еще будет ссылаться на память, где объекта уже десять тысяч тактов как нет.
Задача стоит так: Определить ссылается ли a на существующий или на уничтоженный объект.
Re[4]: Как определить действителен ли указатель?
От: Leonid Troyanovsky  
Дата: 12.09.03 11:05
Оценка:
Здравствуйте, Serginio1, Вы писали:


S> Ну ты и выдернул кусок. Выше описывалось как лучше это делать, но при создании формы все равно создается глобальная переменная и почему бы ее не использовать???


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

Ну,а описано было не как лучше, а, скажем, как всегда.

> Кроме всего прочего до вормы можно добраться и через ee Owner


Для модальных форм обычным делом является AOwner := nil

--
С уважением, LVT.
--
С уважением, LVT
Re[5]: Как определить действителен ли указатель?
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 12.09.03 11:16
Оценка: -1
Здравствуйте, Leonid Troyanovsky, Вы писали:

LT>Здравствуйте, Serginio1, Вы писали:



S>> Ну ты и выдернул кусок. Выше описывалось как лучше это делать, но при создании формы все равно создается глобальная переменная и почему бы ее не использовать???

LT> Чем раньше ты приучишься ими не пользоваться, тем более
LT> пушистыми и шелковистыми будут твои волосы.

Ну а если ссылка на Форму всетаки нужна и время жизни формы неизвестно и заранее известна эта переменная??? Или доступ к форме осуществлять через задницу.

LT> Ну,а описано было не как лучше, а, скажем, как всегда.

Проще по аналогии как в классе TComponent, но со ссылками на объект.


>> Кроме всего прочего до вормы можно добраться и через ee Owner


LT> Для модальных форм обычным делом является AOwner := nil


А для модальных форм вообще нужна ссылка ????

LT>--

LT>С уважением, LVT.
и солнце б утром не вставало, когда бы не было меня
Re[2]: Как определить действителен ли указатель?
От: Leonid Troyanovsky  
Дата: 12.09.03 11:16
Оценка: +1
Здравствуйте, akasoft, Вы писали:


A> with Form2 do

A> begin
A> // Делаем с ней, что надо. Обычно надо ShowModal.

А что еще можно сделать, если следующим идет Free.

A> Free; // Освобождаем, но после работы с формой.

A> end;
A>end;

Вообще, IMHO, следующие строки нужно высечь на здешней стене:

{Показываем модально форму}
with TFormX.Create(nil) do
try
{Устанавливаем необходимое для покакза}
case ShowModal of
..
end;
finally
Free;
end;


A>procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction);

A>begin
A> // Готовимся к закрытию
A> // а затем
A> Form2 := nil;

Ну, _нельзя_ так делать. Мы ООПрограммисты или кто?


A>Обычно делается проверка на равенство nil, например


A>if Assigned(Obj) then

..
A> Obj.Free;

Обычно Obj.Free делает if Assigned(Obj) самостоятельно.

--
С уважением, LVT.
--
С уважением, LVT
Re: Как определить действителен ли указатель?
От: VVP Россия 67524421
Дата: 12.09.03 11:21
Оценка:
Здравствуйте, defrag, Вы писали:

D>Динамически создаю объект, допустим форму

D>Затем, при обработке события от кнопки на этой форме я ее уничтожаю методом Free.
D>
Form2:=TForm2.Create(nil)
...
TForm2.Button1Click(Sender:TObject)
begin
  Free;
end;

Очень плохое "допустим", для форм, в силу некоторых аспектов VCL и Win32, надо вызывать метод Close.

D>Но при этом, указатель Form2 продолжает оставаться инициализированным.

Да, указатель на объект MyObject при вызове MyObject.Free будет по прежнему содержать предыдущее значение, а не nil. В VCL есть процедура SysUtils.FreeAndNil(var aObj), котоый вызывает aObj.Free и проставляет nil в указатель.
D>Вопрос такой, как определить, уничтожен ли объект на который указывает Form2?
Поэтому, если у тебя есть возможность поправить код, то вызывай для своих объектов этот метод, т.е. всегда обнуляй указатели.
D>Вопрос касается не только форм, но и любых наследников TObject иже с ними.
К сожалению, способов определить, что указатель ссылается на "свободный", т.е. отданный менеджеру памяти, блок мне не известно. В принципе можно покопать в сторону менеджера памяти, наверняка что-то есть. Ведь этот BorMM как-то определяет, что блок можно отдать под другой объект.
Никогда не бойся браться делать то, что делать не умеешь. Помни, ковчег был построен любителем. Профессионалы построили Титаник...
Re[6]: Как определить действителен ли указатель?
От: Leonid Troyanovsky  
Дата: 12.09.03 11:34
Оценка:
Здравствуйте, Serginio1, Вы писали:

S>>> Ну ты и выдернул кусок. Выше описывалось как лучше это делать, но при создании формы все равно создается глобальная переменная и почему бы ее не использовать???


LT>> Чем раньше ты приучишься ими не пользоваться, тем более

LT>> пушистыми и шелковистыми будут твои волосы.

S> Ну а если ссылка на Форму всетаки нужна и время жизни формы неизвестно и заранее известна эта переменная??? Или доступ к форме осуществлять через задницу.


Если оная ссылка так тебе дорога, сделай ее полем некоторого класса,
который будет жить дольше формы. Или элементом списка, коллекции,
если не устраивает Screen.Forms. Извещения сможешь получать
через FreeNotification.

LT>> Ну,а описано было не как лучше, а, скажем, как всегда.

S> Проще по аналогии как в классе TComponent, но со ссылками на объект.

Значит, это чрезмерное упрощение.

S> А для модальных форм вообще нужна ссылка ????


Ну, я считаю, что, глобальная переменная не нужна и остальным.
А, в принципе, модальность — это не ледниковый период,
кому-то может и понадобиться. Однако это не может быть
оправданием существованию глобальной переменной.

--
С уважением, LVT.
--
С уважением, LVT
Re[2]: Как определить действителен ли указатель?
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 12.09.03 11:38
Оценка:
Здравствуйте, VVP, Вы писали:

D>>Вопрос касается не только форм, но и любых наследников TObject иже с ними.

VVP>К сожалению, способов определить, что указатель ссылается на "свободный", т.е. отданный менеджеру памяти, блок мне не известно. В принципе можно покопать в сторону менеджера памяти, наверняка что-то есть. Ведь этот BorMM как-то определяет, что блок можно отдать под другой объект.
Была неплохая статья в RSDN. Да и сам GETMEM.INC просмотреть полезно. Но тогда нужно сканировать всю неиспользуемую память, либо по размеру, но так как она может объединяться то и в больших блоках, кроме всего прочего данная память может буть уже отдана другому объекту (переменной).
и солнце б утром не вставало, когда бы не было меня
Re: Как определить действителен ли указатель?
От: Sinclair Россия https://github.com/evilguest/
Дата: 12.09.03 12:10
Оценка: 20 (3) +1
Здравствуйте, defrag, Вы писали:

Правильный ответ: никак.
Т.е. по произвольному указателю нельзя сказать, был ли уже удален объект. Эта память может быть повторно использована под другие объекты.
Еще более правильный ответ: не надо этого делать. Пытаться строить логику программы с проверкой "не умер ли объект" — ошибка проектирования. Время жизни объекта должно контролироваться потребностью в нем. Если объект еще нужен — значит, он должен быть жив. Если объект уже не нужен — не надо лазить по указателям на него.

В Delphi приняты несколько типичных паттернов управления временем жизни:
1. Aggregation. Например, связь по TComponent.Owner. Хозяин компонента отвечает за его смерть. Все формы, созданные через TApplication.CreateForm, гарантированно умрут при завершении приложения. Это очень мощный паттерн; если удается однозначно установить принадлежность одного объекта другому — смело делайте его подчиненным.
Если вы работаете не с TComponent — ничего страшного. В деструкторе хозяина аккуратно вызывайте Free всех его подчиненных. Создавать всех подчиненных сразу в конструкторе не обязательно — в начале все поля инициализируются в Nil, и вызов Free для так и не сконструированных объектов закончится корректно.
2. локальные объекты с синхронным временем жизни. Многие начинающие пренебрегают этой техникой, но на самом деле она очень удобна. Наиболее верный способ избежать проблем с повисшим указателем — не делать указателя:
with TMyForm.Create(nil) do
try
  ShowModal;
finally
    Free;
end;

Это весьма безопасный способ борьбы с объектами.

3. Подсчет ссылок. Если ваш объект "плавает" среди других, и нет никакого объемлющего объекта, реализуйте подходящий интерфейс, и работайте с ним только через указатель на интерфейс. Delphi заставит вас реализовать методы IUnknown, отвечающие за подсчет ссылок. Унаследуйтесь от TInterfacedObject, или подсмотрите в нем реализацию, если наследование невозможно. Помните, что вызов методов _AddRef и _Release будет выполняться автоматически.

4. Высший пилотаж. Если ваши объекты участвуют в циклических зависимостях, то предыдущий способ — верная гарантия утечки памяти. Мне приходилось реализовывать сложные схемы управления временем жизни, например когда создание и уничтожение происходит в разных потоках. Рекомендую постараться применить модификацию способа 1 с передачей владения: ключ к успеху в том, чтобы в каждый момент объект имел одного и только одного хозяина. Хозяин может либо передать объект кому-то еще, либо убить его при своей смерти. Но боже, как это трудно отлаживать!
... << RSDN@Home 1.1 beta 2 >>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[2]: Как определить действителен ли указатель?
От: defrag  
Дата: 12.09.03 12:49
Оценка:
Большое спасибо, что дали конкретный ответ, что нельзя.
Про то, что вледельцы уничтожают своих детей мне известно.
Придется пересроить архитетуру программы. Хотя мои объекты не критичные, уничтожаются при закрытии приложения, а насколько я помню Windows освобождается все ресурсы выделенные процессу при его закрытии
Re[7]: Как определить действителен ли указатель?
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 12.09.03 13:23
Оценка:
Здравствуйте, Leonid Troyanovsky, Вы писали:

LT> Если оная ссылка так тебе дорога, сделай ее полем некоторого класса,

LT> который будет жить дольше формы. Или элементом списка, коллекции,
LT> если не устраивает Screen.Forms. Извещения сможешь получать
LT> через FreeNotification.

Все это я описывал выше только в упрощенном варианте. Чтобы получить FreeNotification владелец должен быть наследником от TComponent. И для этого городить целый класс, особенно когда контроль нужен на протяжении всей жизни программы.

Для каждой задачи нужно находить оптимальный вариант в том числе и обниливание ссылок переданных переменных, да и в обниливание глобальных переменных нет криминала. Это из разряда не использовать GoTo. Но это не значит, что пользуюсь этими методами. Везьде есть свои подводные камни.
А вариантов огромное множество, в том числе и создание разнообразных наследников от TForm итд. Не обязательно городить FreeNotification если можно например обнилить заранее известную переменную, в том числе и переменную класса.
Но опять же все зависит от задачи. И глобальные переменные тоже никто не упразднял.
и солнце б утром не вставало, когда бы не было меня
Re[3]: Как определить действителен ли указатель?
От: akasoft Россия  
Дата: 12.09.03 14:53
Оценка:
Здравствуйте, Leonid Troyanovsky, Вы писали:

LT> А что еще можно сделать, если следующим идет Free.


Что ж, мне теперь не только на лопаточке подавать, но ещё и в рот ложить, челюсти сдвигать/развигать и глотать заставлять?...

LT> Ну, _нельзя_ так делать. Мы ООПрограммисты или кто?


А можно, в частных случаях. Зависит от конкретики задачи. По принципу взведения флага-события.

Сабо сомой, если экземпляров формы много, как, например, в редакторе, то мы пойдём другим путём.

LT> Обычно Obj.Free делает if Assigned(Obj) самостоятельно.


Да, делает. Но без следующей строчки у него крыша поедет.
... << RSDN@Home 1.1 beta 2 >>
Re[7]: Как определить действителен ли указатель?
От: akasoft Россия  
Дата: 12.09.03 14:53
Оценка:
Здравствуйте, Leonid Troyanovsky, Вы писали:

LT> Ну, я считаю, что, глобальная переменная не нужна и остальным.

LT> А, в принципе, модальность — это не ледниковый период,
LT> кому-то может и понадобиться. Однако это не может быть
LT> оправданием существованию глобальной переменной.

А что же надо по-твоему делать с тем, что называют синглтоном?

Вот есть у нас класс Приложение. В одной программе таких классов больше одного быть не может. Или может? Надо заводить в каждой Форме по полю Application? Или же глобальная переменная?

Т.е. где грань разумного?

А давай абстрагируемся на один шаг назад. Пусть процесс наш со всем кодом, глобальными переменнами и пр. будет неким логическим классом TProcess, который создаётся ОС при запуске приложения. А глобальные переменные назовём полями/свойствами этого класса.

Левая рука говорит: "Нас спасут глобальные переменные, только разумно к этому подходи...", а правая: "Забей! Инкапсуляция. ООП. Не сметь глобалить, только члены класса!!!"

Я ещё понимаю, если бы у TObject был метод class function Run, который бы получал управление при запуске. Override и дело с концом. Как в C#...
... << RSDN@Home 1.1 beta 2 >>
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.