Rambler's Top100
"Knowledge itself is power"
F.Bacon
Поиск | Карта сайта | Помощь | О проекте | ТТХ  
 Круглый стол
  
Правила КС
>> Настройки

Фильтр вопросов
>> Новые вопросы
отслеживать по
>> Новые ответы

Избранное

Страница вопросов
Поиск по КС


Специальные проекты:
>> К л ю к в а
>> Г о л о в о л о м к и

Вопрос №

Задать вопрос
Off-topic вопросы

Помощь

 
 К н и г и
 
Книжная полка
 
 
Библиотека
 
  
  
 


Поиск
 
Поиск по КС
Поиск в статьях
Яndex© + Google©
Поиск книг

 
  
Тематический каталог
Все манускрипты

 
  
Карта VCL
ОШИБКИ
Сообщения системы

 
Форумы
 
Круглый стол
Новые вопросы

 
  
Базарная площадь
Городская площадь

 
   
С Л С

 
Летопись
 
Королевские Хроники
Рыцарский Зал
Глас народа!

 
  
ТТХ
Конкурсы
Королевская клюква

 
Разделы
 
Hello, World!
Лицей

Квинтана

 
  
Сокровищница
Подземелье Магов
Подводные камни
Свитки

 
  
Школа ОБЕРОНА

 
  
Арсенальная башня
Фолианты
Полигон

 
  
Книга Песка
Дальние земли

 
  
АРХИВЫ

 
 

Сейчас на сайте присутствуют:
 
  
 
Во Флориде и в Королевстве сейчас  17:51[Войти] | [Зарегистрироваться]
Ответ на вопрос № 45987

18-10-2006 12:12
Здравствуйте!

Я кажется либо наткнулся на огромный косяк в Делфах, либо я чего-то крупно не догоняю.
Предыстория:
Писался список - обертка для TList, который хранил бы не указатели, а варианты. Все было нормально, пока я не решил добавит возможность хранения объектов. Для того, чтобы корректно удалить объект из памяти после удаления элемента списка, надо определить, действительно ли там объект (вариант все-таки), и если он там есть, то удалить его. Для определения того, что в варианте находится указатель на объект, запись туда объекта производится так:

  type varTmp: Variant;
  objTmp: TObject;
  TVarData(varTmp).VType:=vtObject;
  TVarData(varTmp).VPointer:=Tmp;


При этом всегда можно проверить что хранится в варианте, через проверку TVarData(varTmp).VType, и извлечь оттуда сам объект через TVarData(varTmp).VPointer. Но тут всплыла очень странная проблема, которую проще всего проиллюстрировать кодом:


program class_variant;

{$APPTYPE CONSOLE}

var
  varTmp: Variant;
  objTmp: TObject;
begin
  // создаем
  objTmp:=TObject.Create;
  TVarData(varTmp).VType:=vtObject;
  TVarData(varTmp).VPointer:=objTmp;
  // получаем
  writeln(TObject(TVarData(varTmp).VPointer).ClassName);
  // удаляем
  TObject(TVarData(varTmp).VPointer).Free;
  // объект по прежнему существует ?
  writeln(objTmp.ClassName); // да! <== Здесь по идее AV
  writeln(TObject(TVarData(varTmp).VPointer).ClassName); // да!!?
  readln;
end.


Результат:

TObject
TObject
TObject


Все три вывода сработали! И никаких AV.
Упс! А что тогда я удалил?... Получается объект в варианте живет и после самого удаления, либо мы удалем совсем не то. Но если этот код еще можно осмыслить что-ли, то вот это:

program class_variant;

{$APPTYPE CONSOLE}

type
  TMyObj = class(TObject)
    procedure SayHello;
    constructor Create;
    destructor Destroy; override;
  end;

{ TMyObj }

constructor TMyObj.Create;
begin
  writeln('obj created');
end;

destructor TMyObj.Destroy;
begin
  writeln('obj deleted');
  inherited;
end;

procedure TMyObj.SayHello;
begin
  writeln('hello!');
end;

var
  varTmp: Variant;
  objTmp, objTmpRef: TMyObj;
begin
  // создаем
  objTmp:=TMyObj.Create;
  TVarData(varTmp).VType:=vtObject;
  TVarData(varTmp).VPointer:=objTmp;
  // извлекаем
  objTmpRef:=TMyObj(TVarData(varTmp).VPointer);
  // удаляем
  objTmpRef.Free;
  // удалили?
  objTmpRef.SayHello;
  //
  readln;
end.


Результат:

obj created
obj deleted
hello!


Без комментариев.

Может кто-то сможет мне помочь удалить объект? Заранее спасибо.

[+] Добавить в избранные вопросы

Отслеживать ответы на этот вопрос по RSS

Ответы:


Уважаемые авторы вопросов! Большая просьба сообщить о результатах решения проблемы на этой странице.
Иначе, следящие за обсуждением, возможно имеющие аналогичные проблемы, не получают ясного представления об их решении. А авторы ответов не получают обратной связи. Что можно расценивать, как проявление неуважения к отвечающим от автора вопроса.

03-01-2007 16:29 | Сообщение от автора вопроса
Кстати, то как я в итоговом коде запихиваю TObject в Variant делать нельзя, хотя бы потому , что написано в самом System.pas по этому поводу:
{ if adding new items, update Variants' varLast, BaseTypeMap and OpTypeMap }
А я этого не сделал.
Так что я изначально был не прав. Простите меня пожайлуста. Всем еще раз большое спасибо!

10-12-2006 03:49 | Комментарий к предыдущим ответам
>>> полностью освободить тот кусок памяти
Попробуй свернуть-развернуть программу и только после этого вызывать SayHello - вот теперь вероятность AV значительное повысится. То же самое происходит при вызове SetProcessWorkingSetSize (см. соответствующие обсуждения). То есть менеджер памяти будет удерживать кусок, пока операционка вежливо не попросит его вернуть все, что взял на место или пока программа не завершится. К нестандартным менеджерам памяти это может не относиться.

19-10-2006 07:38 | Сообщение от автора вопроса
Так, походу я наворотил...
...должен заметить, что вы неправильно работаете с вариантами: константа vtObject не имеет к ним ни малейшего отношения, она связана с работой TVarRec и конструкции "array of const"
Да, я ошибся. Писал по аналогии - VarType - vt... А оказалось значения начинаются с префикса var. Буду знать теперь.
Насчет создания своего вариантного типа, думал над этим, но мне-то и надо всего хранить в варианте указатель на объект, и при удалении варианта вызвать деструктор объекта. И при этом точно знать, что в варианте хранится указатель, а не число. Для этого я вручную правил значение VType, но как оказалось неправильно.
VariantClear?
Насколько я понял, эта функция очистит только значение варианта, и никаких деструкторов при этом вызываться не будет. А я как раз хотел удалить не вариант, а то, куда ссылается указатель, хранящийся в нем.
Уже после того, как я отравил вопрос, я нашел еще одну проблему в своем коде: я неправильно проверял "надежность" удаления объекта. Я это делал вызовом его метода, а как я обнаружил, если метод объекта не использует его поля либо является статическим, то он работает и до создания, и после удаления объекта. А вот если попытаться получить доступ к полю, то и получим желанную ошибку.
Вот работающий код:

program class_variant;

{$APPTYPE CONSOLE}

const
  varObject = $0015;

type
  TMyObj = class(TObject)
    SomeField: string;
    procedure SayHello;
    constructor Create;
    destructor Destroy; override;
  end;

{ TMyObj }

constructor TMyObj.Create;
begin
  writeln('obj created');
end;

destructor TMyObj.Destroy;
begin
  writeln('obj deleted');
  inherited;
end;

procedure TMyObj.SayHello;
begin
  writeln(SomeField);
end;

function GetObjFromVar(v: Variant): TObject;
begin
  if TVarData(v).VType=varObject then
    result:=TObject(TVarData(v).VPointer)
  else result:=nil;
end;

var
  objTmp, objTmpRef: TMyObj;
  varTmp: Variant;
begin
  objTmp:=TMyObj.Create;
  objTmp.SomeField:='hello!';
  // записываем
  TVarData(varTmp).VType:=varObject;
  TVarData(varTmp).VPointer:=objTmp;
  // получаем
  objTmpRef:=TMyObj(GetObjFromVar(varTmp));
  objTmpRef.SayHello;
  // удаляем
  GetObjFromVar(varTmp).Free;
  //
  objTmp.SomeField:='hi!'; // <== УРА! Память не может быть "read" ...
  readln;
end.


Спасибо за помощь!

18-10-2006 12:59 | Комментарий к предыдущим ответам
Чёрт! "помечается как свободная" конечно же.

18-10-2006 12:59
VariantClear?

Вот чо в справке написано:

VarClear procedure

Empties a Variant, so that it is unassigned.

Unit

System

Category

Variant support routines

Delphi syntax:

procedure VarClear(V: Variant);

C++ syntax:

extern PACKAGE void __fastcall  VarClear(Variant& v);

Description

Calling VarClear is equivalent to assigning the Unassigned constant to the Variant. V can be either a Variant or an OleVariant, but it must be possible to assign a value to it (it must be an lvalue).

After calling VarClear, the VarIsEmpty function returns true, and the VarType function returns varEmpty. Using an unassigned variant in an expression causes an exception to be thrown. Likewise, if you attempt to convert an unassigned Variant to another type (using VarAsType ), an exception is thrown.

Note:
Do not confuse clearing a Variant, which leaves it unassigned, with assigning a Null value. A Null Variant is still assigned, but has the value Null. Unlike unassigned Variants, Null Variants can be used in expressions and can be converted to other types of Variants.

18-10-2006 12:58
Объект это просто участок памяти, соответственно при удалении объекта эта память помечается как удалённая и более ничего. А AV вы получите только если менеджер памяти решит полностью освободить тот кусок памяти в котором помещался ваш объект, но вероятность этого довольно мала.
Потом должен заметить, что вы неправильно работаете с вариантами: константа vtObject не имеет к ним ни малейшего отношения, она связана с работой TVarRec и конструкции "array of const". В дельфи есть возможность создавать свои типы вариантов, но делается это намного сложнее вашего способа (смотрите Variants.pas), а так вы не получите ничего кроме ошибки, потому что ваша константа vtObject совпадает с varDate, то есть в ваших вариантах должна содержаться дата, а не объект.

18-10-2006 12:34
FreeAndNil?

Добавьте свое cообщение

Вашe имя:  [Войти]
Ваш адрес (e-mail):На Королевстве все адреса защищаются от спам-роботов
контрольный вопрос:
Кто съел Красную шапочку?
в качестве ответа на вопрос или загадку следует давать только одно слово в именительном падеже и именно в такой форме, как оно используется в оригинале.
Надоело отвечать на странные вопросы? Зарегистрируйтесь на сайте.
Тип сообщения:
Текст:
Жирный шрифт  Наклонный шрифт  Подчеркнутый шрифт  Выравнивание по центру  Список  Заголовок  Разделительная линия  Код  Маленький шрифт  Крупный шрифт  Цитирование блока текста  Строчное цитирование
  • вопрос Круглого стола № XXX

  • вопрос № YYY в тесте № XXX Рыцарской Квинтаны

  • сообщение № YYY в теме № XXX Базарной площади
  • обсуждение темы № YYY Базарной площади
  •  
     Правила оформления сообщений на Королевстве

    Страница избранных вопросов Круглого стола.
      
    Время на сайте: GMT минус 5 часов

    Если вы заметили орфографическую ошибку на этой странице, просто выделите ошибку мышью и нажмите Ctrl+Enter.
    Функция может не работать в некоторых версиях броузеров.

    Web hosting for this web site provided by DotNetPark (ASP.NET, SharePoint, MS SQL hosting)  
    Software for IIS, Hyper-V, MS SQL. Tools for Windows server administrators. Server migration utilities  

     
    © При использовании любых материалов «Королевства Delphi» необходимо указывать источник информации. Перепечатка авторских статей возможна только при согласии всех авторов и администрации сайта.
    Все используемые на сайте торговые марки являются собственностью их производителей.

    Яндекс цитирования