Как убедиться, что объект не уничтожен

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

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

Как убедиться, что объект не уничтожен

Сообщение Brainenjii » 17.07.2011 12:50:45

Сабж ^_^ Assigned и проверка на nil не помогают.
Код: Выделить всё
Var
  i: Integer;
  aList: TList;
  aObject1: TObject;
Begin
  aList := TList.Create;
  aObject1 := TObject.Create;
  aList.Add(aObject1);
  FreeAndNil(aObject1);
  For i := 0 To aList.Count - 1 Do
    Try
      If Assigned(aList[i]) And Not(aList[i] = nil) Then // <- Не поможет
        Write(TObject(aList[i]).ToString);
    Except On E: EAccessViolation Do
      WriteLn('Не помогло :-(');
    End;
  aList.Free;
End.
Аватара пользователя
Brainenjii
энтузиаст
 
Сообщения: 1351
Зарегистрирован: 10.05.2007 00:04:46

Re: Как убедиться, что объект не уничтожен

Сообщение MageSlayer » 17.07.2011 13:07:38

Brainenjii писал(а):Сабж ^_^ Assigned и проверка на nil не помогают.

Разумеется не помогают. И не помогут. Не делайте этого.

Если вам в нужно что-то такое в паскале, то это значит одно из следующего:
-вы не понимаете, что вы делаете и рано или поздно ваша "архитектура" развалится;
-вместо интерфейсов вы неправильно выбрали объекты;
-вы неверно выбрали язык.
MageSlayer
постоялец
 
Сообщения: 216
Зарегистрирован: 07.09.2006 12:30:44

Re: Как убедиться, что объект не уничтожен

Сообщение Odyssey » 17.07.2011 14:20:35

MageSlayer прав.

Здесь важно помнить, что aObject1 и aList[0] -- это два разных указателя на один и тот же объект в куче. FreeAndNil освобождает объект (т.е. кусок памяти в куче) и обнуляет один из указателей, но не второй. Второй после уничтожения объекта продолжает указывать в область памяти, которая уже не принадлежит объекту (и возможно, принадлежит кому-то другому).

Если нужно работать с несколькими указателями на один и тот же объект, я обычно делаю так:
- мысленно выделяю из всех указателей один "основной" (условно считаю, что это и есть сам объект). Он создаётся через конструктор и освобождается через FreeAndNil. Просто присвоить ему nil (или любое другое значение) нельзя, это приведёт к утечке памяти.
- все остальные указатели на этот объект считаются ссылками. Им можно присваивать только указатели на уже существующие объекты, либо nil. Выделение/освобождение памяти через конструктор/деструктор для ссылок запрещено, это приведёт к утечкам памяти/EAccessViolation.
- выделяю экземпляр класса (например, TObjectList), ответственный за операции с "самими" объектами. Удалить существующий объект из памяти можно только через запрос к этому классу (напр. TObjectList.Delete). Перед удалением самого объекта необходимо удалить, либо обнулить ( := nil) все ссылки на этот объект.
- обозначаю переменную-"сам объект" и переменные-ссылки на уровне текста программы: комментариями или именованием (напр. MyObject, MyObjectRef).
Odyssey
энтузиаст
 
Сообщения: 580
Зарегистрирован: 29.11.2007 17:32:24

Re: Как убедиться, что объект не уничтожен

Сообщение debi12345 » 17.07.2011 17:32:53

Разумеется не помогают. И не помогут. Не делайте этого.

Частный случай, ИМХО.
Почему бы самому не писать custom- классы - деструкторы которых (на FreeAndNil) освобождают все внутренние динамические объекты ?
Аватара пользователя
debi12345
долгожитель
 
Сообщения: 5759
Зарегистрирован: 10.05.2006 23:41:15
Откуда: Ташкент (Узбекистан)

Re: Как убедиться, что объект не уничтожен

Сообщение Maxizar » 17.07.2011 18:16:23

Может я не понял вопроса, но почему все говояр мол так нельзя??? Непонятно, вообще-то льзя, но ошибка из-за вот этого:
Код: Выделить всё
  FreeAndNil(aObject1);

После этого в листе у нас указатель есть (ведь его никто не дулалил нетак ли) и он указывал в свое время до ФрииАндНил на наш класс (объект) а после? правильно он указывает тудаже, но там уже тю тю...

Или в чем был вопрос то?
Просто если вы ждали, что при удалении объекта обнулится поинтер в листе?
Просто судя по этому:
Код: Выделить всё
Assigned(aList[i]) And Not(aList[i] = nil)

Вы именно этого ждали?
Если да, то одисей уже написал, про указатель ссылок и все такое, если просто хотите юзать списки (TList) То я делаю как то так:
Код: Выделить всё
unit Unit1;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls;

type

  { TForm1 }

  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
  private
    { private declarations }
  public
    { public declarations }
  end;

var
  Form1: TForm1;
  List:TList;

implementation

{$R *.lfm}

{ TForm1 }

procedure TForm1.Button2Click(Sender: TObject);  //Удаления последнего (хвоста)
begin
if (List<>Nil) and (List.Count>0) then
  begin
    TForm(List[List.Count-1]).Free;
    List.Delete(List.Count-1);              //Обязательно иначе полная чушь
  end;
end;

procedure TForm1.Button3Click(Sender: TObject);
begin
if (List<>Nil) and (List.Count>0) then
   TForm(List[List.Count-1]).Show;               //Показываем хвостик
end;

procedure TForm1.Button1Click(Sender: TObject);  //Создание в данном случае 10 окон
var I:Integer;
    NF:TForm;
begin

  if List = nil then
    List:=TList.Create;

  For I:=1 to 10 do
   begin
     NF:=TForm.Create(Nil);
     NF.Caption:=IntToStr(I);
     List.Add(NF);
   end;
end;

end.


Для Объектов типа Object
Код: Выделить всё
unit Unit1;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls;

type

  { TForm1 }

  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
  private
    { private declarations }
  public
    { public declarations }
  end;


  { TComplexObject }
  PMyObject=^TMyObject;
  TMyObject = Object
    I:Integer;
    S:String;
    constructor Create(vI:Integer; vS:String);
  end;

var
  Form1: TForm1;
  List:TList;

implementation

{ TComplexObject }

constructor TMyObject.Create(vI:Integer; vS:String);
begin
   I:=vI;
   S:=vS;
end;

{$R *.lfm}

{ TForm1 }

procedure TForm1.Button2Click(Sender: TObject);  //Удаления последнего (хвоста)
begin
if (List<>Nil) and (List.Count>0) then
  begin
    Dispose(PMyObject(List[List.Count-1]));
    List.Delete(List.Count-1);              //Обязательно иначе полная чушь
  end;
end;

procedure TForm1.Button3Click(Sender: TObject);
begin
if (List<>Nil) and (List.Count>0) then
   Caption:= PMyObject(List[List.Count-1])^.S;               //Показываем хвостик
//Либо так Caption:= TMyObject(List[List.Count-1]^).S;
end;

procedure TForm1.Button1Click(Sender: TObject);  //Создание в данном случае 10 окон
var I:Integer;
    NO:PMyObject;
begin

  if List = nil then
    List:=TList.Create;

  For I:=1 to 10 do
   begin
     NO:=New(PMyObject);
     NO^.Create(I, 'Строка№ '+IntToStr(I));
     List.Add(NO);
   end;
end;

end.


PS. Что-то я перегрелся, даже вопросы недопонимаю (:...
Maxizar
постоялец
 
Сообщения: 385
Зарегистрирован: 20.03.2010 19:48:14

Re: Как убедиться, что объект не уничтожен

Сообщение stikriz » 19.07.2011 22:04:52

Хороший препод на третьем курсе должен подойти к человеку, который не понимает указателей и сказать, что надо переходить на поток менеджеров. В программерах делать нечего.
По существу. Только интерфейсы помогут, внимание, НЕ УДАЛИТЬ объект, если он присвоен действительной используемой переменной.
Понять, что адрес в указателе указывает на уничтоженный или не уничтоженный объект невозможно.
У меня два указателя, и я FreeAndNil сделал с одним из них... И что во втором? Некий недествительный адрес...

Добавлено спустя 2 минуты 42 секунды:
Кстати, можно в менеджере памяти сделать проверку указателя на дейстывительность. Но, это, по моему, крайне неэффкутивно. Видимо, нужно еще и список какой создать на каждый указатель, а при FreeMem искать этот указатель и удалять из списка... Хрень. Лучше осторожно пользоваться указателями.
Аватара пользователя
stikriz
энтузиаст
 
Сообщения: 612
Зарегистрирован: 15.03.2006 09:37:47

Re: Как убедиться, что объект не уничтожен

Сообщение hinst » 19.07.2011 22:37:28

Собственно, а TObjectList на щито? он разве не занимается тем, что настраивает там какие-то указатели на события, и каким-то образом когда объект Free, он его удаляет из списка? По-моему, если использовать TObjectList в примере автора, всё сразу станет хорошо. А если не станет, то TComponentList уж точно должен помочь (помню, был такой)
Аватара пользователя
hinst
энтузиаст
 
Сообщения: 781
Зарегистрирован: 12.04.2008 18:32:38

Re: Как убедиться, что объект не уничтожен

Сообщение Brainenjii » 19.07.2011 23:11:05

Ну, мало ли, вдруг как-то решена проблема, а я и не знал йцу Вообще, что мешает один бит адреса использовать под флаг "актуальности" объекта. 32 битные ОСи (в большинстве своем) все-равно разрешают только 2 Гб использовать, а между 2^63 и 2^64 на практике и разницы нет ^_^ Или там забивать при разрушении область объекта тем же deadbeef'ом, и при обращении проверять...
Ну, нет так нет, печально ^_^
P.S. проблема, которая побудила к старту топика уже решена некоторым подобием сборщика мусора - вместо уничтожения ставил флаг "удалить", и в определённый момент пробегался по всем нужным спискам и удалял из них объекты и только после этого освобождал... Но все-равно, принципиальная невозможность проверки корректности ссылки на объект огорчает
Аватара пользователя
Brainenjii
энтузиаст
 
Сообщения: 1351
Зарегистрирован: 10.05.2007 00:04:46

Re: Как убедиться, что объект не уничтожен

Сообщение stikriz » 20.07.2011 10:35:38

Есть такой паттерн, что есть кто-то, кто создал объект. У него может быть список объектов, которые он создал. Когда объект уничтожается, то он лезет в этот список и удаляет самого себя из него. И все - мы всегда знаем, кого уж нет...
Аватара пользователя
stikriz
энтузиаст
 
Сообщения: 612
Зарегистрирован: 15.03.2006 09:37:47

Re: Как убедиться, что объект не уничтожен

Сообщение Brainenjii » 20.07.2011 10:48:01

У меня почти так и есть (объект сам себя, правда добавляет в этот общий список).
Аватара пользователя
Brainenjii
энтузиаст
 
Сообщения: 1351
Зарегистрирован: 10.05.2007 00:04:46

Re: Как убедиться, что объект не уничтожен

Сообщение Odyssey » 20.07.2011 13:07:01

hinst писал(а):Собственно, а TObjectList на щито? он разве не занимается тем, что настраивает там какие-то указатели на события, и каким-то образом когда объект Free, он его удаляет из списка?

TObjectList - наоборот. Когда объект удаляют из списка (TObjectList), то этот список освобождает объект, если у списка OwnsObjects = True. А если мы сами освободим объект, позже получим Access Violation.

TComponentList - да, ведёт себя именно так (судя по документации). Вот он как раз и реализует
stikriz писал(а):паттерн, что есть кто-то, кто создал объект. У него может быть список объектов, которые он создал. Когда объект уничтожается, то он лезет в этот список и удаляет самого себя из него.

Но чтобы этим воспользоваться, все свои классы, которые складываются в список, придётся наследовать от TComponent.
Odyssey
энтузиаст
 
Сообщения: 580
Зарегистрирован: 29.11.2007 17:32:24

Re: Как убедиться, что объект не уничтожен

Сообщение wavebvg » 20.07.2011 18:47:02

Можно добавить указатель на "уникальный" хеш в базовый объект (деструктор объекта хеш "портит"), тогда, проверив этот хеш можно узнать, существует ли объект или нету (Правда будет существовать определенная вероятность, что хеш совпадет случайно).
Вот только данная необходимость при правильном проектировании возникнуть не должна...
wavebvg
постоялец
 
Сообщения: 354
Зарегистрирован: 28.02.2008 04:57:35

Re: Как убедиться, что объект не уничтожен

Сообщение Mr.Smart » 20.07.2011 19:50:22

wavebvg угу и словить эксепшен доступа к памяти.
Mr.Smart
долгожитель
 
Сообщения: 1796
Зарегистрирован: 29.03.2008 01:01:11
Откуда: из леса!

Re: Как убедиться, что объект не уничтожен

Сообщение hinst » 20.07.2011 20:34:40

Говорю вам, TComponentList лучше всех. Всегда его заюзываю!
Аватара пользователя
hinst
энтузиаст
 
Сообщения: 781
Зарегистрирован: 12.04.2008 18:32:38

Re: Как убедиться, что объект не уничтожен

Сообщение wavebvg » 21.07.2011 16:15:52

Mr.Smart писал(а):wavebvg угу и словить эксепшен доступа к памяти.

Ну это надо ещё постараться, поскольку память выделяется не побитно
wavebvg
постоялец
 
Сообщения: 354
Зарегистрирован: 28.02.2008 04:57:35


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

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

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

Рейтинг@Mail.ru