Страница 1 из 1

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

СообщениеДобавлено: 17.07.2011 12:50:45
Brainenjii
Сабж ^_^ 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.

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

СообщениеДобавлено: 17.07.2011 13:07:38
MageSlayer
Brainenjii писал(а):Сабж ^_^ Assigned и проверка на nil не помогают.

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

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

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

СообщениеДобавлено: 17.07.2011 14:20:35
Odyssey
MageSlayer прав.

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

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

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

СообщениеДобавлено: 17.07.2011 17:32:53
debi12345
Разумеется не помогают. И не помогут. Не делайте этого.

Частный случай, ИМХО.
Почему бы самому не писать custom- классы - деструкторы которых (на FreeAndNil) освобождают все внутренние динамические объекты ?

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

СообщениеДобавлено: 17.07.2011 18:16:23
Maxizar
Может я не понял вопроса, но почему все говояр мол так нельзя??? Непонятно, вообще-то льзя, но ошибка из-за вот этого:
Код: Выделить всё
  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. Что-то я перегрелся, даже вопросы недопонимаю (:...

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

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

Добавлено спустя 2 минуты 42 секунды:
Кстати, можно в менеджере памяти сделать проверку указателя на дейстывительность. Но, это, по моему, крайне неэффкутивно. Видимо, нужно еще и список какой создать на каждый указатель, а при FreeMem искать этот указатель и удалять из списка... Хрень. Лучше осторожно пользоваться указателями.

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

СообщениеДобавлено: 19.07.2011 22:37:28
hinst
Собственно, а TObjectList на щито? он разве не занимается тем, что настраивает там какие-то указатели на события, и каким-то образом когда объект Free, он его удаляет из списка? По-моему, если использовать TObjectList в примере автора, всё сразу станет хорошо. А если не станет, то TComponentList уж точно должен помочь (помню, был такой)

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

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

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

СообщениеДобавлено: 20.07.2011 10:35:38
stikriz
Есть такой паттерн, что есть кто-то, кто создал объект. У него может быть список объектов, которые он создал. Когда объект уничтожается, то он лезет в этот список и удаляет самого себя из него. И все - мы всегда знаем, кого уж нет...

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

СообщениеДобавлено: 20.07.2011 10:48:01
Brainenjii
У меня почти так и есть (объект сам себя, правда добавляет в этот общий список).

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

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

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

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

Но чтобы этим воспользоваться, все свои классы, которые складываются в список, придётся наследовать от TComponent.

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

СообщениеДобавлено: 20.07.2011 18:47:02
wavebvg
Можно добавить указатель на "уникальный" хеш в базовый объект (деструктор объекта хеш "портит"), тогда, проверив этот хеш можно узнать, существует ли объект или нету (Правда будет существовать определенная вероятность, что хеш совпадет случайно).
Вот только данная необходимость при правильном проектировании возникнуть не должна...

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

СообщениеДобавлено: 20.07.2011 19:50:22
Mr.Smart
wavebvg угу и словить эксепшен доступа к памяти.

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

СообщениеДобавлено: 20.07.2011 20:34:40
hinst
Говорю вам, TComponentList лучше всех. Всегда его заюзываю!

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

СообщениеДобавлено: 21.07.2011 16:15:52
wavebvg
Mr.Smart писал(а):wavebvg угу и словить эксепшен доступа к памяти.

Ну это надо ещё постараться, поскольку память выделяется не побитно