Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2007.05.20;
Скачать: CL | DM;

Вниз

Проблема удаления объектов в 0-ом элемента коллекции (TCollectio)   Найти похожие ветки 

 
duhast ©   (2007-03-22 12:41) [0]

Кто-нибудь работал тесно с коллекциями в Делфи?
У меня возникла такая проблема - существют 2 созданнх мной класса
TMNSB_DetailObjItem и TMNSB_DetailObjCollection. У элемента коллекции есть 2 поля тип объекта и сам объект. Объект создаётся и инициализируется вне (на стороне :) ) НУ в конце-концов мне, при удалении коллекции, нужно освобождать память от объекта в элементе коллекции. Так вот проблема возникает при уделении 0-го элемента коллекции (как известно дестрой происходит с n-го элемента по 0-й) - память из под него просто не освобождается.
Вот код описания:

TMNSB_DetailObjItem = class (TCollectionItem)
     private
      FObjClass: TClass;
      FObj: TObject;
     public
      property ObjClass: TClass read FObjClass write FObjClass;
      property Obj: TObject read FObj write FObj;

      {constructor/destructor}
      destructor Destroy; override;
     end;

   TMNSB_DetailObjCollection = class (TCollection)
     private
      function GetItem(Index: Integer): TMNSB_DetailObjItem;
      procedure SetItem(Index: Integer; Value: TMNSB_DetailObjItem);
     public
      function Add: TMNSB_DetailObjItem;
      property Item[Index: integer]: TMNSB_DetailObjItem read GetItem write                  SetItem; default;
     end;

Код деструктора:

destructor TMNSB_DetailObjItem.Destroy;
begin

 Obj.Free;
// Если 0-й то проверям что там с ним
 If Self.Index = 0 then
  Begin  
  // If Assigned (obj) then  obj.Free
   Showmessage(Obj.ClassName);
  end;
 inherited;
end;


Вот такой вот код, если раскоментировать строку   If Assigned (obj) then  obj.Free - то возникает исключительная ситуация - типа я его уже закосил - проверяю есть ли там что то - есть !! - тогда удали... - там нефига нету и вообще непонятно что там --->  вылет!!!!
Кто с таким сталкивался пожайлуста помогите!!! Или скажите что не так.


 
clickmaker ©   (2007-03-22 12:55) [1]

а как создание и удаление происходит?


 
ЮЮ ©   (2007-03-22 13:00) [2]

> Obj.Free;
> // Если 0-й то проверям что там с ним


И чего теперь уже проверять, если уничтожен? А ссылка естестенно остаоась. И Assigned (obj) будет true.


 
Плохиш ©   (2007-03-22 13:01) [3]

Да и текст исключения не помешает в оригинале.


 
ЮЮ ©   (2007-03-22 13:09) [4]

> Объект создаётся и инициализируется вне (на стороне :) )
>


А может они (объекты) и уничтожаются не стороне? И к моменту уничтожения элементов коллекции уже имеем битые ссылки?


 
duhast ©   (2007-03-22 14:55) [5]

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

O: Tobject;
.......................

if DCE.GetCollectRef then
 Begin
   with DCE.DomainByName("ref").DmnDetailCollection do
     begin
      O := TMNSBObject(item[0].Obj as item[0].ObjClass);
      free;
      Edit1.text := TMNSBObject(o).DomainByName("2").DmnValue;
    end;

Так вот когда Итем не 0-й то прога удачно вылетает при обращении к объекту
(Error (EAccessViolation): Access viokation at adress  --- ну короче понятно), а вот когда Итем 0-й то все отлично отрабатывается, без всяких глюков.

Причем в коллекции 4 элемента и деструктор срабатывает тоже 4-и раза и 0-й элемнт якобы тоже грохает, но блин как оказывается - нет.


 
duhast ©   (2007-03-22 15:08) [6]

Коллекция грохает только свои элементы, а об том что создано в элементе коллекции она не заботится (проверено!!!!), поэтому и дистрою. После удаления коллекции при обращении к преждевременно сохранёным ссылкам на объект данные сохраняются - тобиж объекты весят в памяти, а вот когда я грохаю принудительно их (см. выше) все бы хорошо - только вот блин 0-й чёто ей ненравится :))))


 
icWasya ©   (2007-03-22 17:55) [7]

Что за код ???
O: Tobject;
.......................

if DCE.GetCollectRef then
Begin
  with DCE.DomainByName("ref").DmnDetailCollection do
    begin
     O := TMNSBObject(item[0].Obj as item[0].ObjClass); // слишком сложно, хватило бы O := item[0].Obj;
     free; // а это к чему????
     Edit1.text := TMNSBObject(o).DomainByName("2").DmnValue;
   end;


 
duhast ©   (2007-03-22 19:22) [8]

Незная специфики задачи давайте не обсуждать
Пишу ЕЩЁ РАЗ!!!!

DCE.GetCollectRef  - вызов метода объекта
DCE.DomainByName("ref") колекция доменов объекта
DmnDetailCollection - коллекция детализации (с её то элементами я работаю)
Получается "коллекция в коллекции"
O := TMNSBObject(item[0].Obj as item[0].ObjClass); - сохраняю ссылку на объект

FREE - освобождаю память из под коллекции детализации, всё что с ней связано должно быть уничтожено(и item[0].Obj и item[1].Obj и item[n].Obj).
(DCE.DomainByName("ref").DmnDetailCollection), деструктор её элемента уничтажает все связанные с ним объекты!!!!!!
Потом обращаюсь по заранее сохранённой ссылке (O) к объекту 0-го элемената кол-ции и О ЧУДО !!! он ещё существует в отличии от других объектов не 0-го элемента кол-ции - они благополучно уничтожены!!!!!
А вот он радимы сел и не вредим.


 
duhast ©   (2007-03-22 19:26) [9]

Это всего лиш пример (тест) проверяющий всё ли "загребает" за собой удаляемая коллекция - оказывается не всё, у кого подобный код работает отлично прошу, под бурные авации предоставить его сдесь, пожайлуста!


 
Юрий Зотов ©   (2007-03-22 20:10) [10]

Н-да...

destructor TMNSB_DetailObjItem.Destroy;
begin
 Obj.Free; // Объект убит. Ссылку на него никто не чистил и она осталась.
 If Self.Index = 0 then // Зачем тут Self? Он будет и так.
 Begin  
   If Assigned (obj)  // Даст true - ведь ссылку никто не чистил.
     then obj.Free // Здравствуй, глюк!!!
   Showmessage(Obj.ClassName); // Здравствуй, второй глюк!!!
  end;
 inherited;
end;

Второй глюк к тому же еще и двойной, поскольку обращение к объекту происходит после его аж ДВОЙНОГО уничтожения (LOL!). Впрочем, до второго глюка дело никогда не дойдет - будет валиться на первом.

Что и наблюдается.

Выкиньте этот, извините, бред, и оставьте просто:

destructor TMNSB_DetailObjItem.Destroy;
begin
 Obj.Free;
 inherited;
end;

И если после этого работать снова не будет, то ищите причину в ДРУГОМ месте. Но уж ТОЧНО не здесь.


 
Юрий Зотов ©   (2007-03-22 20:20) [11]

if DCE.GetCollectRef then
Begin
  with DCE.DomainByName("ref").DmnDetailCollection do
    begin
     O := TMNSBObject(item[0].Obj as item[0].ObjClass); // ???
     free; // *
     Edit1.text := TMNSBObject(o).DomainByName("2").DmnValue;
   end;

В строке, помеченной звездочкой, грохается коллекция. При этом, согласно коду VCL, она грохает свои Item"ы, а те, согласно коду нашего деструктора, грохают связанные с ними объекты.

После чего переменная O указывает уже не на объект (только что убитый), а куда-то в сторону Луны. И на следующей строке при вызове DomainByName снова получаем "Здравствуй, глюк!".

Поменяйте местами две этих строки.

А строку, помеченную ??? явно писал индус. Это не ошибка, работать она будет - но писал ее явно индус.

А о нулевом/ненулевом индексе забудьте. Они здесь ни при чем. Если они где-то и глючат, то не в этом месте.


 
duhast ©   (2007-03-23 01:22) [12]

Многоуважаемый Юрий Зотов :) спасибо за пост.
Первоначалньно деструктор так и выглядел:

destructor TMNSB_DetailObjItem.Destroy;
begin
Obj.Free;
inherited;
end;


Данный замути типа If Assigned (obj) then obj.Free были добавлены  в целях проверить сущиствует ли глюк - на "вылет" это и предполагалось организовать для проверки 0-го элемента.

>В строке, помеченной звездочкой, грохается коллекция. При этом, согласно
>коду VCL, она грохает свои Item"ы, а те, согласно коду нашего деструктора,
>грохают связанные с ними объекты.

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

destructor TMNSB_DetailObjItem.Destroy;
begin
Obj.Free;
inherited;
end;


уничтажается все кроме объекта 0-го  элемента, т.е. я могу ОБРАТИТСЯ к нему и взять его значени - чего по логике недолжно происходить - так как он УДАЛЁН уже. к 1-му и так далее немогу обратится так как они успешно удалены и происхдоит логичный вылет, а вот последний 0-й весит .

Насчёт строки  O := TMNSBObject(item[0].Obj as item[0].ObjClass);- соглаcен :)))

Короче, окончательно привожу пример:
Дупустим в коллекции 4-элемента

if DCE.GetCollectRef then
Begin
 with DCE.DomainByName("ref").DmnDetailCollection do
   begin
    O := item[0].Obj ;// сохраняю
    free; // удаляю
    Edit1.text := TMNSBObject(O).DomainByName("2").DmnValue;   -  СТРАННО, НО                                  
    РАБОТАЕТ!!!!!!!!!!!! (возвращает значение)
  end;
--------------------------------------------------------------
if DCE.GetCollectRef then
Begin
 with DCE.DomainByName("ref").DmnDetailCollection do
   begin
    O := item[1].Obj ;// сохраняю (тоже и для 2-го и 3-го)
    free; // удаляю
    Edit1.text := TMNSBObject(O).DomainByName("2").DmnValue;   -  вылетает -            так и должно работать (Логично :))
  end;


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


 
DrPass ©   (2007-03-23 01:44) [13]


> уничтажается все кроме объекта 0-го  элемента, т.е. я могу
> ОБРАТИТСЯ к нему и взять его значени - чего по логике недолжно
> происходить - так как он УДАЛЁН уже

Глупости. Если ты удаляешь объект - это не значит, что программа тут же побежит затирать ту память, в которой он лежал. Ни в коем случае. Она просто пометит его участок памяти как свободный, чтобы при случае записать туда что-либо новое. Естественно, после вызова Free сам объект никуда не делся, и если ты сохранил на него ссылку, вполне возможно что он даже будет как-то там работать... некоторое время...


 
ЮЮ ©   (2007-03-23 03:46) [14]

Edit1.text := TMNSBObject(O).DomainByName("2").DmnValue;   -  СТРАННО, НО                                  
   РАБОТАЕТ!!!!!!!!!!!! (возвращает значение)


> вполне возможно что он даже будет как-то там работать...
> некоторое время...


А ты попробуй не читать, а вызвать метод, который "пишет" в память и посмотри как оно работает


 
duhast ©   (2007-03-23 12:02) [15]

>А ты попробуй не читать, а вызвать метод, который "пишет" в память и посмотри как оно >работает

Все прекрасно пашет в 0-ом элементе. Записывает значение в якобы уже удаллёный элемент по сохранённой ссылке (после Free ) и его же считывает нормально. - Чего быть не должно.

>Глупости. Если ты удаляешь объект - это не значит, что программа тут же побежит затирать >ту память, в которой он лежал. Ни в коем случае. Она просто пометит его участок памяти как >свободный, чтобы при случае записать туда что-либо новое. Естественно, после вызова Free >сам объект никуда не делся, и если ты сохранил на него ссылку, вполне возможно что он даже >будет как-то там работать... некоторое время...

Так  почему же интересно не 0-е элементы не считываются, всё по той жё причине освобождения памяти, а 0-й считывается по вашей так сказать "будет как-то там работать... некоторое время..." - Причём считывается из разных методов (я думал может он в пределах одного метода будет считываться а в других типа уже исчезнет - но это просто глупости :) )

НУ короче я так понял никто из сдесь постивших не сталкивался с такой задачей:
Уничтожить все объекты связанные с эл-том коллекции - тобиж закриэйтить и проинициализировать их в ввыших класах или гденибудь на стороне, а потом при дестрое  убить их всех до последнего. Я вот просто был рад что вся созданная система пашет - но когда меня осинило проверить всёли за собой убирает коллекция - оказалось что нет - вот теперь и сижу ломаю голову почему это так. Когда то я столкнулся с глюком в компоненте ADO (работа с рекордсетами - "перебор" рекордсетов), хочу надеятся что с коллекциями не будет глюков в реализации, может гдето я чего не досмотрел - но уже много пересматриваю и всё логично написано и не только я смотрел.


 
DrPass ©   (2007-03-23 12:33) [16]


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

Нам бы твои проблемы...


 
Gadenysh   (2007-03-23 15:35) [17]

сделай FreeAndNil, если так уж сильно тебе нужно


 
Gadenysh   (2007-03-23 15:42) [18]

и в деструкторе inherited лучше всеже первым ставить


 
Gadenysh   (2007-03-23 15:46) [19]


> Gadenysh   (23.03.07 15:42) [18]
> и в деструкторе inherited лучше всеже первым ставить


херню сказал. прошу прощения



Страницы: 1 вся ветка

Текущий архив: 2007.05.20;
Скачать: CL | DM;

Наверх




Память: 0.54 MB
Время: 0.084 c
15-1177080727
ArtemESC
2007-04-20 18:52
2007.05.20
PHP


2-1177962098
vegarulez
2007-04-30 23:41
2007.05.20
Вопрос про DBGrid.(Перемещение по гриду, сколько записей видно)


2-1178187372
ganda
2007-05-03 14:16
2007.05.20
Неотлавливает горячую клавишу компонет ApplicationEvents


4-1166351587
Windows
2006-12-17 13:33
2007.05.20
WinSock функция определения коннекта


2-1177790801
dzhagr
2007-04-29 00:06
2007.05.20
Ошибка SQL