как правильно проверять существование обьекта ?

Вопросы программирования на Free Pascal, использования компилятора и утилит.

Модератор: Модераторы

Аватара пользователя
Attid
долгожитель
Сообщения: 2589
Зарегистрирован: 27.10.2006 17:29:15
Откуда: 44°32′23.63″N 41°2′25.2″E
Контактная информация:

как правильно проверять существование обьекта ?

Сообщение Attid »

как правильно проверять существование обьекта ?

знаю два способа

generic_icons: TStringList;

if Assigned(generic_icons) then

and

if generic_icons <> nil then

оба не правильные и не работают =)
Logo
постоялец
Сообщения: 464
Зарегистрирован: 20.08.2008 01:00:47

Сообщение Logo »

В fpc 2.2.4 под linux вроде правильно работает, проблема была в 2.2.0 или 2.2.2

А это всегда работает.

Код: Выделить всё

  
   if generic_icons is TStringList then Label1.Caption := 'Yes'
   else Label1.Caption := 'No';
Mr.Smart
долгожитель
Сообщения: 1796
Зарегистрирован: 29.03.2008 00:01:11
Откуда: из леса!

Сообщение Mr.Smart »

Logo писал(а):А это всегда работает.

Код: Выделить всё

  
   if generic_icons is TStringList then Label1.Caption := 'Yes'
   else Label1.Caption := 'No';

Если переменная не инициализированна то получите ошибку доступа к памяти!

to Attid при объявлении объекта инициализируюте его как nil

Код: Выделить всё

var generic_icons: TStringList = nil;

при уничтожении пользуйтесь процедурой FreeAndNil
Vadim
долгожитель
Сообщения: 4112
Зарегистрирован: 05.10.2006 08:52:59
Откуда: Красноярск

Сообщение Vadim »

Функция Assigned() тоже просто проверяет объект на NIL, так что если переменную не проинициализировать NIL'ом, то проверить, адрес в ней объекта или шелуха, невозможно.
Можно, конечно, проверять и так, как предложил Mr.Smart

Код: Выделить всё

Try
  {Любое обращение к объекту}
Except
  on EAccessViolation do
    ShowMessage('ФигВам а не объект');
End;

Но лучше инициализировать, кода меньше...
Logo
постоялец
Сообщения: 464
Зарегистрирован: 20.08.2008 01:00:47

Сообщение Logo »

Mr.Smart писал(а):
Logo писал(а):А это всегда работает.

Код: Выделить всё

  
   if generic_icons is TStringList then Label1.Caption := 'Yes'
   else Label1.Caption := 'No';

Если переменная не инициализированна то получите ошибку доступа к памяти!

А проверить трудно?

Я так понял, что у Attid не стандартная ситуация. Не тот уровень у него, чтобы не понять если переменная не nil, то ее не стоит проверять на nil.
Mr.Smart
долгожитель
Сообщения: 1796
Зарегистрирован: 29.03.2008 00:01:11
Откуда: из леса!

Сообщение Mr.Smart »

Logo писал(а):Я так понял, что у Attid не стандартная ситуация. Не тот уровень у него, чтобы не понять если переменная не nil, то ее не стоит проверять на nil.

Вопрос был имено о проверки на существование объекта, а не на проверку принадлежнасти к классу.
Аватара пользователя
Sergei I. Gorelkin
энтузиаст
Сообщения: 1409
Зарегистрирован: 24.07.2005 14:40:41
Откуда: Зеленоград

Сообщение Sergei I. Gorelkin »

В общем случае это практически невозможно. Оператор 'is', завернутый в try..except, конечно, вернет true в случае, когда возможно прочитать sizeof(Pointer) байт памяти по заданному указателю и когда эти sizeof(Pointer) байт представляют собой указатель на VMT нужного нам класса, либо на VMT его потомка. Но это ничего не говорит ни о доступности, ни о состоянии остальных полей объекта. И даже если они доступны, это может оказаться только что уничтоженный объект, который будет переписан через пару миллисекунд...

Проще следить за тем, что записывается в переменную.
Logo
постоялец
Сообщения: 464
Зарегистрирован: 20.08.2008 01:00:47

Сообщение Logo »

Sergei I. Gorelkin писал(а):...И даже если они доступны, это может оказаться только что уничтоженный объект, который будет переписан через пару миллисекунд...

Проще следить за тем, что записывается в переменную.

Согласен на все 100%. Сам так и делаю.
Мне уже трудно найти код, написанный год назад, но при желании можно. Так вот там возникла ситуация, где гарантии нет, что неинициализированная переменная будет nil, - проверка на принадлежность к классу и выручила. Ситуация, что класс был удален, да может быть, но алгоритм программы это не предусматривал и я уверен, что этого не произойдет. Не по теории? - Конечно, но работает, а все мы по теории делаем? Что, никто классы не крякает для доступа к приватным полям? (хотя сам сейчас эту практику прекратил)

Зная по форуму Attid`а, мне и в голову не пришло, что он не смог разобраться с инициализацией переменных, я крупно сомневаюсь, что он не знал о том, что поля в классах инициализируются(обнуляются), а внешние переменные нет. Предположив, что ситуация нестандартная, я и предложил "нестандартный" метод проверки. Принимать его или нет - дело его.
Аватара пользователя
alexs
долгожитель
Сообщения: 4069
Зарегистрирован: 15.05.2005 23:17:07
Откуда: г.Ставрополь
Контактная информация:

Сообщение alexs »

В этой ситуации самое правильное решение - FreeAndNil использовать ВСЕГДА!
Аватара пользователя
Attid
долгожитель
Сообщения: 2589
Зарегистрирован: 27.10.2006 17:29:15
Откуда: 44°32′23.63″N 41°2′25.2″E
Контактная информация:

Сообщение Attid »

ой понаписали =)

1, польщен =) но гуру тоже могут ошибаться особенно в конце дня особенно в выходной =))

2, FreeAndNil это хорошо когда ты его должен освободить, но не помогает если его не создали. но передают как созданный.


Sergei I. Gorelkin писал(а):В общем случае это практически невозможно.

чего и требовалось доказать. спасибо.
Аватара пользователя
Иван Шихалев
энтузиаст
Сообщения: 1138
Зарегистрирован: 15.05.2006 11:26:13
Откуда: Екатеринбург
Контактная информация:

Сообщение Иван Шихалев »

Attid писал(а):если его не создали. но передают как созданный

А в этом случае линейкой по рукам хорошо — помогает.
Max Rusov
постоялец
Сообщения: 191
Зарегистрирован: 25.04.2009 15:46:03

Сообщение Max Rusov »

Тогда другая (уже практически осмысленная) задача. Есть объект, из него вызывается какая-то процедура. В результате сложной, непредсказуемой последовательности событий при выходе из этой процедуры может оказаться так что наш объект уже был уничтожен, соотв. обращаться к его полям и свойствам нельзя. Хочется отследить эту ситуацию и как-то обработать, например кинуть Abort. Как это сделать наиболее эффективно?
Аватара пользователя
Sergei I. Gorelkin
энтузиаст
Сообщения: 1409
Зарегистрирован: 24.07.2005 14:40:41
Откуда: Зеленоград

Сообщение Sergei I. Gorelkin »

Так, вообще-то, оказваться не должно. И механизмы для того, чтобы этого не происходило, есть разные:
1) Интерфейсы+подсчет ссылок (объект не удаляется до тех пор, пока его кто-то использует)
2) Уведомление об уничтожении (TComponent.FreeNotification и сотоварищи)
3) Отложенное удаление (объект ставится в очередь и уничтожается несколько позже, когда уже можно. См. TForm.Release).
4) Не удалять вообще, в конце концов.
Max Rusov
постоялец
Сообщения: 191
Зарегистрирован: 25.04.2009 15:46:03

Сообщение Max Rusov »

2 - для данной задачи не поможет
4 - это не решение проблемы, это отказ от решения.
1 и 3, да это путь. Но зачастую слишком сложный, может потребоваться перепроектировать пол системы.

Пример задачи: есть некий интерфейс-билдер с кнопочками и событиями OnClick. Что напишут в обработчике OnClick -
заранее неизвестно, могут убить и кнопочку, и форму на которой она лежит. В "обычном" языке - это приведет к AV - сам дурак.
А вот в "защищенной" среде - хотелось бы выдать цивильную ошибку...
Logo
постоялец
Сообщения: 464
Зарегистрирован: 20.08.2008 01:00:47

Сообщение Logo »

Max Rusov писал(а):Тогда другая (уже практически осмысленная) задача. Есть объект, из него вызывается какая-то процедура. В результате сложной, непредсказуемой последовательности событий при выходе из этой процедуры может оказаться так что наш объект уже был уничтожен, соотв. обращаться к его полям и свойствам нельзя. Хочется отследить эту ситуацию и как-то обработать, например кинуть Abort. Как это сделать наиболее эффективно?

Я у себя выкрутился из подобной ситуации таймером. После подачи команды на удаление, сначала блокируется доступ к объекту и запускается таймер на гарантированное время, чтобы все внутренние операции закончились. После истечения заданного времени, объект уничтожается. Можно и счетчик обращений с блокировкой применить, но с таймером оказалось проще.

Добавлено спустя 11 минут 26 секунд:
Max Rusov писал(а):Пример задачи: есть некий интерфейс-билдер с кнопочками и событиями OnClick. Что напишут в обработчике OnClick -
заранее неизвестно, могут убить и кнопочку, и форму на которой она лежит. В "обычном" языке - это приведет к AV - сам дурак.
А вот в "защищенной" среде - хотелось бы выдать цивильную ошибку...


Наверное переписывать Destroy и вводить проверку, если вызов сделан от потомка, то блокировать. Хотя, как это реализовать, на данный момент не представляю.
Ответить