Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 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, и кину вопрос в форум (и тебе на мыло напишу), ну а там уж как сложится - будет ли у кого свободное время и желание или нет.



Страницы: 1 вся ветка

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

Наверх





Память: 0.51 MB
Время: 0.006 c
14-91079
M-A-B
2002-02-13 08:52
2002.03.28
СОМ-порт


3-90814
OlgaSf
2002-03-05 11:36
2002.03.28
WebSnap: формирование условий выборки из БД


1-90971
Surprising
2002-03-15 01:21
2002.03.28
Ограничение по времени работы программы


3-90746
AnIg
2002-02-28 18:21
2002.03.28
Кто работал с DBChart ? Что за эффект?


3-90791
Sewix
2002-02-28 10:32
2002.03.28
Отчет





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский