Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Проблема удаления объектов в 0-ом элемента коллекции (TCollectio) [D7, WinXP]


duhast ©   (2007-03-22 12:41:00) 

Кто-нибудь работал тесно с коллекциями в Делфи?
У меня возникла такая проблема - существют 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 - то возникает исключительная ситуация - типа я его уже закосил - проверяю есть ли там что то - есть !! - тогда удали... - там нефига нету и вообще непонятно что там --->  вылет!!!!
Кто с таким сталкивался пожайлуста помогите!!! Или скажите что не так.


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


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


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


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

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


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

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


DrPass   (2007-03-23 12:33:00) [4]


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

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


duhast   (2007-03-23 12:02:00) [5]

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

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

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

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

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


ЮЮ   (2007-03-23 03:46:00) [6]

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


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


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


DrPass   (2007-03-23 01:44:00) [7]


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

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


duhast   (2007-03-23 01:22:00) [8]

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

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;


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


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

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 снова получаем "Здравствуй, глюк!".

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

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

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


Юрий Зотов   (2007-03-22 20:10:00) [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;

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


duhast   (2007-03-22 19:26:00) [11]

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


duhast   (2007-03-22 19:22:00) [12]

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

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-го элемента кол-ции - они благополучно уничтожены!!!!!
А вот он радимы сел и не вредим.


icWasya   (2007-03-22 17:55:00) [13]

Что за код ???
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 15:08:00) [14]

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


duhast   (2007-03-22 14:55:00) [15]

Коллекция заполняется в др. модуле, в поле эл-та кол-и записывается объект приведённый к типу 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-й элемнт якобы тоже грохает, но блин как оказывается - нет.


ЮЮ   (2007-03-22 13:09:00) [16]

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


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


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

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


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

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


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


clickmaker   (2007-03-22 12:55:00) [19]

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


Наверх

Титульная страница Поиск, карта сайта Написать письмо