![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Проблема удаления объектов в 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]а как создание и удаление происходит?