Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Delphi программирование > Общие вопросы Delphi
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 14.12.2010, 10:57   #1
Sibedir
Тот ещё
Старожил
 
Аватар для Sibedir
 
Регистрация: 14.11.2007
Сообщений: 2,242
По умолчанию Проверить выделена ли память под объект

Опять столкнулся с проблемой, с которой периодически сталкиваются все программисты, разрабатывающие циклически вложенные структуры. Необходимо знать, инициализирован объект или пока/уже нет. Есть несколько решений. Можно после Free делать := nil. Можно использовать FreeAndNil. Но если есть еще один указатель на этот же объект, и нет возможности/желания следить за инициализацией/уничтожением объектов, то возникает проблема. Даже если уничтожить и обнилить один из указателей на объект, другие всеравно будут продолжать хранить его старый адрес.
Вот как я решил эту проблему. Может не ново, но я ничего подобного по теме не нашел.

Смотрим
Код:
type
...

  TMyO = class
  private
    FAssigned: Pointer;
  protected

  public
    constructor Create;
    procedure Free;
    function Assigned: Boolean;
  end;

...


implementation

...

procedure TfrmTesting.Button6Click(Sender: TObject);
var
  o1, o2: TMyO;
begin
  o1 := TMyO.Create;
  o2 := o1;

  if o1.Assigned then ShowMessage ('Оk');
  if o2.Assigned then ShowMessage ('Оk');

//  FreeAndNil (o2);
  o1.Free;

  if o1.Assigned then ShowMessage ('Bad');
  if o2.Assigned then ShowMessage ('Bad');
end;

...

{ TMyO }

function TMyO.Assigned: Boolean;
begin
  Result := (Self <> nil) and (FAssigned = Self);
end;

constructor TMyO.Create;
begin
  inherited Create;

  FAssigned := Self;
end;

procedure TMyO.Free;
begin
  FAssigned := 0;
  inherited Free;
end;

...
Высказываем свое мнение

P.S.: Сразу замечу, вероятность ошибки 1/4294967296 = 2.328e-8%. Можно еще уменьшить вероятность ошибки, используя
Код:
  TAssigned = record
    V1, V2: Pointer;
  end;

  TMyO = class
  private
    FAssigned: TAssigned;
  protected

  public
    constructor Create;
    procedure Free;
    function Assigned: Boolean;
  end;
Sibedir вне форума Ответить с цитированием
Старый 14.12.2010, 11:45   #2
Аватар
Старожил
 
Аватар для Аватар
 
Регистрация: 17.11.2010
Сообщений: 18,922
По умолчанию

Насчет вероятности спорно. Вы обращаетесь к методу объекта удаленного по Free. Память ранее занимаемая им может очень быстро изменена, а может и не очень. В результате можете получить полнейший шах и мат
Если бы архитекторы строили здания так, как программисты пишут программы, то первый залетевший дятел разрушил бы цивилизацию
Аватар вне форума Ответить с цитированием
Старый 14.12.2010, 12:09   #3
TwiX
Участник клуба
 
Аватар для TwiX
 
Регистрация: 28.07.2009
Сообщений: 1,510
По умолчанию

Это вероятность ошибки в ближайшее время после удаления. Т.е. это очень ненадежный метод.
И вообще зачем так заморачиваться? Никак не могу придумать ситуации, где нельзя обойтись без использования одного указателя, поэтому считаю, что FreeAndNill более чем достаточно.
TwiX вне форума Ответить с цитированием
Старый 14.12.2010, 13:19   #4
Serge_Bliznykov
Старожил
 
Регистрация: 09.01.2008
Сообщений: 26,229
По умолчанию

согласен с мнением Аватар и TwiX, предложенный Вами способ нарушает принципы ООП - вполне возможна ситуация (причём с высокой вероятностью), что при обращении к методу объекта, который мы освободили - получим Access Violation!
Если так уже необходимо иметь несколько указателей на одну и ту же область память (я тоже не представляю ситуацию, когда без этого нельзя обойтись), но тогда надо придумывать свой механизм, где фиксировать, какой из указателей освободился. Разумеется, этот механизм не должен быть завязан на использовании свойств и методов тех объектов, которые мы удаляем...
(например, в вышеприведённом примере:
Код:
  FreeAndNil(O1);
  if Not Assigned(O1) or Not Assigned(O2) then {BAD}...
Ну и пользоваться (всегда) надо не .Free - а FreeAndNil - с занулением указателя...
Serge_Bliznykov вне форума Ответить с цитированием
Старый 14.12.2010, 14:10   #5
Sibedir
Тот ещё
Старожил
 
Аватар для Sibedir
 
Регистрация: 14.11.2007
Сообщений: 2,242
По умолчанию

Цитата:
вполне возможна ситуация (причём с высокой вероятностью), что при обращении к методу объекта, который мы освободили - получим Access Violation!
Она возникнит только тогда, когда объект уничтожен, ссылка <> nil, а FAssigned = Self. А с учетом
Код:
procedure TMyO.Free;
begin
  FAssigned := 0;
  inherited Free;
end;
Вероятность как раз порядка 1e-8% (при TAssigned = record - 1e-18%, можно довести до уровня вероятности совпадения GUID).
Цитата:
Никак не могу придумать ситуации, где нельзя обойтись без использования одного указателя
Вот как выглядит начало описания моего класса. Обращаем внимание на выделенное
Код:
  TSibObject = class
  private
    FOwner             : Pointer            ; // Хозяин объекта
    FChanged           : Boolean            ; // Был ли изменен объект с момента открыия или последнего сохранения
    FReadOnly          : Boolean            ; // Доступен только для чтения
    FInfluencingObjects: array of TSibObject; // (ВЛИЯЮЩИЕ) Список объектов, от которых зависит данный объект
    FDependentObjects  : array of TSibObject; // (ЗАВИСИМЫЕ) Список объектов, которые зависят от данного объекта
Поверьте, там есть такие ситуации. Зависимости между объектами могут быть как паутина в старом чулане.
Цитата:
надо придумывать свой механизм, где фиксировать, какой из указателей освободился
Будет много накладных расходов. Не ругаемся, щас объясню. Если сделать такой механизм, он будет работать всегда, даже когда не нужен. Но в том то вся и штука, что мне это нужно иногда. А если иногда, в запутанных ситуациях, пользоваться TMyO.Assigned, то это не будет кушать ресурсы.
Но вообще-то, там есть такой механизм. При изменении объекта, оповещаются все зависимые объекты. Проблемы возникают, когда имеется многопоточность.
Кстати, критические данные (непосредственно относящиеся к расчетам, прикладные), такой ситуации не подвержены. Они не удаляются абы как. Там все четко.

Хотя не могу не согласится в одном. Смотрится это как-то угрожающе. Как затишье перед бурей. По большому счету, надо менять логику, а то нагорожу лес, сам потом не пройду.

Добавил ----------------------------------------------------
Кстати, FreeAndNil вообще не вариант. Но она сама по себе не виновата. Она использует TObject.Free, а он не динамический и перегрузить ее не удастся. Получается, что все, что я писал во Free своего класса, выполнено не будет. Идея хорошая. Но лучше уж тогда свою такую процедурку написать через Destroy или через
Код:
  TMyCustomObject = class
  private
  protected
    procedure Free; virtual;
  public
  end;

Последний раз редактировалось Sibedir; 14.12.2010 в 14:29.
Sibedir вне форума Ответить с цитированием
Старый 14.12.2010, 14:17   #6
Utkin
Старожил
 
Аватар для Utkin
 
Регистрация: 04.02.2009
Сообщений: 17,351
По умолчанию

Вопрос - все объекты являются экземплярами одного класса?
Маньяк-самоучка
Utkin появился в результате деления на нуль.
Осторожно! Альтернативная логика
Utkin вне форума Ответить с цитированием
Старый 14.12.2010, 14:32   #7
Sibedir
Тот ещё
Старожил
 
Аватар для Sibedir
 
Регистрация: 14.11.2007
Сообщений: 2,242
По умолчанию

Не, ну почему сразу все. Там куча потомков будет. Но родительский класс у всех будет TSibObject. А что?
Sibedir вне форума Ответить с цитированием
Старый 14.12.2010, 14:37   #8
Utkin
Старожил
 
Аватар для Utkin
 
Регистрация: 04.02.2009
Сообщений: 17,351
По умолчанию

Есть предложение использовать хеш под это дело. Потом если вдруг идет сслыка на не существующий идентификатор, то и объекта нет и все дела. Вам нужен хеш объектов. Пусть существует единый менеджер объектов - он создает и уничтожает объекты и раздает ключи (или идентификаторы). Если ключ не действителен, то и объекта нет.
Маньяк-самоучка
Utkin появился в результате деления на нуль.
Осторожно! Альтернативная логика
Utkin вне форума Ответить с цитированием
Старый 14.12.2010, 15:00   #9
Sibedir
Тот ещё
Старожил
 
Аватар для Sibedir
 
Регистрация: 14.11.2007
Сообщений: 2,242
По умолчанию

Ну, да. Думал я над этим. Даже Create в protected запихал, чтоб кто ни попадя не создавал чего не просят. Специальную функцию создания написал и динамический массив скрытый (правда щас их чет не наблюдаю, ну да ладно). В итоге получается лишняя промежуточная ссылка. И получается она всегда. А мне всегда не надо.
Ну короче. Надо все объекты разбить на две логические группы. За одними буду следить (хранится они будут в дин. массиве, а в программе буду использовать ссылки на ссылки), а с другими буду работать аккуратно, так, чтобы следить не пришлось.
Sibedir вне форума Ответить с цитированием
Старый 14.12.2010, 15:05   #10
Utkin
Старожил
 
Аватар для Utkin
 
Регистрация: 04.02.2009
Сообщений: 17,351
По умолчанию

Промежуточная ссылка избавляет Вас от геморроя . Это плохо? По мне так лучше лишние десять байт завести чем гадать выпадет седня прога в осадок или не выпадет...
Маньяк-самоучка
Utkin появился в результате деления на нуль.
Осторожно! Альтернативная логика
Utkin вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Неправильно выделена память. С++ Purr Помощь студентам 7 31.10.2010 20:05
Как передвигать объект если он не под формой.VB somebody94 Помощь студентам 1 29.06.2010 10:07
Объект PageSetup. Как проверить пустые ли колонтитулы в документе Word?? =) YaponskijGorodovoj Компоненты Delphi 0 09.06.2010 23:09
динамически выделить память под верхний треугольник квадратной матрицы juventine Общие вопросы C/C++ 2 12.04.2009 13:06
Память, выделяемая под приложение. Altera Компоненты Delphi 4 30.11.2008 18:13