Форум: "Основная";
Поиск по всему сайту: delphimaster.net;
Текущий архив: 2002.03.28;
Скачать: [xml.tar.bz2];




Вниз

Как однозначно проверить, существует ли объект (создан ли, не испорчен ли)? 


lipskiy   (2002-03-16 16:40) [0]

Достаточно ли делать проверку на nil, или еще что-то можно для надежности?



wicked   (2002-03-16 16:43) [1]

если придерживаться определённых правил программирования, то проверка на nil - достаточна....



Anatoly Podgoretsky   (2002-03-16 16:49) [2]

Почему у тебя возникла необходимость проверки, обычно это ошибка проектирования, а так никак.



kull   (2002-03-16 16:58) [3]

Вообще-то достаточно
Правда есть нюансы:
MyObject.Free;
после этого если ссылаться на MyObject то там может быть всякий мусор,и проверка на нил ничего не даст.

В лучшем случае возникнет Access Violation.

Поэтому рекомендую сделать так:
MyObject.Free;
MyObject := nil;

если, конечно собираешься обращаться к этой переменной в дальнейшем.




Anatoly Podgoretsky   (2002-03-16 17:04) [4]

В дельнейшем к этой переменной надо обращать так
MyObject := TMyObject.Create и проверка не потребуется



lipskiy   (2002-03-16 17:14) [5]

Все верно, если писать грамотно.
Но вот я пишу неграмотно.
Затесалась ошибка в коде - и не могу ее отловить.
Возникает при обращении к объекту, проверка на nil проходит, а объекта нет.

Вообще-то, бывают ли ситуации, когда кривыми руками можно испортить область памяти, занимаемую объектом?
В этом случае nil не даст эффекта. А free мне делать нельзя - я же хочу работать с объектом, а не заново его создавать. Но когда он испорчен - нужно просто это корректно обработать.



wicked   (2002-03-16 17:44) [6]

2 lipskiy ©
а если испорчен - ничем не поможешь... разве что хранить контрольные суммы для всех экземпляров обьектов... :)
лучше всего - пересмотри алгоритмы, упрости... найди сомнительные места и перепиши их по новой...



Anatoly Podgoretsky   (2002-03-16 18:12) [7]

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



evgeg   (2002-03-16 18:19) [8]

Переменная типа класс - это указатель. Он может указывать куда угодно. Проверка на nil не поможет.
Можно, конечно, свой распределитель памяти написать. Как, написано на http://www.delphikingdom.com.



kull   (2002-03-16 19:04) [9]


> Правильнее писать так, что бы такой потребности не возникала,
> единственное место где требуется проверка на nil, это назначен
> ли обработчик событию, но там проблемы не возникает


Проверка на nil может потребоваться в любом месте, даже если писать супер грамотно.

Особенно если в проекте учавствуют несколько разработчиков.


> В дельнейшем к этой переменной надо обращать так
> MyObject := TMyObject.Create и проверка не потребуется

еще как может потребоваться...

А если переменная хранила экземпляр объекта, и этот объект уничтожили (за ненадобностью),а переменная используется для последующей работы?
естественно после Free устанавливать в nil чтобы следующая проверка Assigned(переменная) прошла успешно.



Anatoly Podgoretsky   (2002-03-16 19:11) [10]

Ни разу не потребовалось использовать повторно переменную, поэтому и не было нужды присваивать ей nil, а срок достаточно больщой и проекты сложные, это зависит от того как писать.
Повторное использование переменноц рпно иди поздно приведет к ошибке. Но уж если используется, то обязательно надо приваивать и проверять



lipskiy   (2002-03-16 19:13) [11]

Ок, все понял. Надо баг искать, а не обходить его.
Тогда скажите мне, правильно ли переприсваивать объекты через переменные?
Например (в моем проекте, в частности), есть TreeView.
По выбору новой ноды происходит некое действие.
Но перед этим действием нужно выполнить код по снятию выбора с предыдущей ноды.
Ну, например, TreeView управляет Мемой. В Меме можно редактировать текст, который должен автоматически сохраняться перед выбором другой ноды и загрузкой нового текста.

Что я делаю. На событие OnChange вешаю обработчик, в котором выполняется код по закрытию предыдущей ноды, а потом по открытию текущей. При этом предыдущую ноду я запоминаю в переменной, так как OnChange выдает мне сразу текущую.
Получается примерно следующее:

var
PrevNode:TTreeNode;

procedure TForm1.TreeViewChange(Sender:TObject; Node:TTreeNode);
begin
// вызываю метод по обработке закрытия предыдущей ноды:
ClosePrevNode(PrevNode);
// обрабатываю открытие новой ноды:
OpenNewNode(Node);
// запоминаю ноду для следующего раза:
PrevNode:= Node;
end;


Можно ли так делать - PrevNode:= Node?




bad-md   (2002-03-16 19:26) [12]

-> lipskiy:

Можно, если после уничтожения "TreeView" - PrevNode нигде не используете, можно даже:

procedure TForm1.TreeViewChange(Sender:TObject; Node:TTreeNode);
const
PrevNode: TTreeNode = nil;
begin
// вызываю метод по обработке закрытия предыдущей ноды:
ClosePrevNode(PrevNode);
// обрабатываю открытие новой ноды:
OpenNewNode(Node);
// запоминаю ноду для следующего раза:
PrevNode:= Node;
end;


А где у вас "AV"-то выскакивает?

With best wishes



lipskiy   (2002-03-16 20:38) [13]

2 bad-md
> А где у вас "AV"-то выскакивает?
К сожалению, очень сложно объяснить. Но попробую привести свой код без лишнего. Если кому не в лом будет разобраться и указать на явную глупость - буду благодарен.

Я создаю TreeView динамически, и на каждую ноду вешаю рекорд со списком разных параметров, в т.ч. и событий.
Вот описание:

type
PntRec = ^TRec;
TRec = record
FName: String; // обрабатываемый нодой файл
EOnSelect: TTVChangedEvent; // событие по выбору ноды
EOnDeSelect: TTVChangedEvent; // событие по снятию выбора ноды
// и еще список параметров разных типов
end;

var
RecPtr: PntRec;

type
TSTreeView = class (TTreeView)
private
SelNode,PrevNode:TTreeNode; // текущая и предыдущая выделенная нода
.......
procedure Change(Node: TTreeNode); override;
procedure FOnChange(Sender:TObject; Node:TTreeNode);
.......
public
function sAddItem(... см. ниже)
end;


Теперь создаю ветки, примерно так:

function TSTreeView.sAddItem(
Caption: String;
Tree: TTreeNode;
FName: String;
OnSelect: TTVChangedEvent;
OnDeSelect: TTVChangedEvent):TTreeNode;
var
Node:TTreeNode;
begin
New(RecPtr);
RecPtr^.FName:= FName;
RecPtr^.EOnSelect:= OnSelect;
RecPtr^.EOnDeSelect:= OnDeSelect;
Node:= Items.AddObject(Tree, Caption, RecPtr);
Result:= Node;
end;


Дальше вешаю обработчик на открытие ноды.
Для некоторых целей прищлось перекрыть метод Change, внутри него пишу примерно следующее:

procedure TSTreeView.Change(Node: TTreeNode);
begin
//... некоторые проверки
if Node = nil then exit;
if Node.Data = nil then exit;
FOnChange(Self,Node); // вызываю основной обработчик
//... некоторые проверки
inherited Change(Node);
end;


И, наконец, основной обработчик, в котором и происходит AV:

procedure TSTreeView.FOnChange(Sender:TObject; Node:TTreeNode);

// вложенная процедурка обработки ноды
procedure ServiceNode(Node:TTreeNode);
begin
PrevNode:= SelNode; // запоминаем в буфер предыдущей ноды
SelNode:= Node; // запоминаем в буфер текущей ноды
// далее производятся некотрые неопасные действия с Node:
// (меняю цвет шрифта, выделения, обновляю историю переходов)
end;

begin
// если на ноду не назначено обработчика - ничего с ней не делаем
if not Assigned(PntRec(Node.Data)^.EOnSelect) then exit;

// если повторно кликнули по той же ноде - тоже не обрабатываем
if Node = SelNode then exit;

ServiceNode(Node); // сменились SelNode и PrevNode

if PrevNode <> nil then
if PrevNode.Data <> nil then
if Assigned(PntRec(PrevNode.Data)^.EOnDeSelect) then // << ЗДЕСЬ AV !!!
PntRec(PrevNode.Data)^.EOnDeSelect(Sender,PrevNode);

PntRec(SelNode.Data)^.EOnSelect(Sender,SelNode);
end;


Важное замечание: Ошибка нестабильная, чаще всего не происходит. И останов происходит не всегда на указанной строчке, иногда немного дальше - после выхода из FOnChange, но еще до выхода из Change.
Заметил еще, что ошибка происходит, когда бегаю по нескольким нодам мышкой подряд. Причем ошибка вылетает через интервал времени задержки выбора ноды (свойство ChangeDelay). Если я ChangeDelay устанавливаю в ноль, то ошибка не возникает или возникает значительно реже.



Набережных С.   (2002-03-17 12:40) [14]

В приведенном коде нет никаких поводов для AV, что и подтвердилось при проверке. Ошибка где-то в другом месте. Кстати, вместо рекорда я бы использовал объект. Если хочешь, сбрось проект мне на мыло(только .dpr, .pas и .dcu), посмотрю, пока есть время.

И по более раннему поводу. Необходимость проверки на nil - вполне дежурная ситуация. Хрестоматийный пример:
Проект содержит множество форм, некоторые из них могут потребоваться не в каждом сеансе. Создавать их все на старте и постоянно держать в памяти бессмысленно. Следовательно, при обращении:
if MyArtfulForm = nil then MyArtfulForm = Application.CreateForm...
Если форма используется достаточно редко, то есть смысл уничтожать ее после использования - опять же требуется проверка.
Это самый очевидный пример, но и других поводов немало.
Этого легко избежать при функциональном программировании, но не при событийном, когда последовательность исполнения кода невозможно предсказать.
Или я не прав?



lipskiy   (2002-03-17 15:07) [15]

2 Набережных С.
Спасибо большое за предлагаемую помощь, но смотреть мой проект - это, по-моему unreal - в нем порядка 20 модулей и десяток нестандартных компонентов и библиотек.
Позже, если получиться, я подгтотовлю проект без лишнего, но с AV, и кину вопрос в форум (и тебе на мыло напишу), ну а там уж как сложится - будет ли у кого свободное время и желание или нет.




Форум: "Основная";
Поиск по всему сайту: delphimaster.net;
Текущий архив: 2002.03.28;
Скачать: [xml.tar.bz2];




Наверх





Память: 0.77 MB
Время: 0.031 c
3-90731           Snake                 2002-02-27 18:39  2002.03.28  
BDE в терминал-клиенте.


1-90929           Vadimir               2002-03-13 16:37  2002.03.28  
Графика...


1-90972           ivit61                2002-03-13 10:52  2002.03.28  
Поиск метода по адресу


1-90831           AndreyS               2002-03-14 15:34  2002.03.28  
Вопрос по приорететам и компилятору.


1-90855           HELP!!!!!!!!!!!!!!!   2002-03-16 09:18  2002.03.28  
ПОМОЩЬ!!