![]() |
|
Модераторы: Snowy, MetalFan, bems, Poseidon |
![]()
|
|
| PsiMagistr |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 479 Регистрация: 31.12.2009 Репутация: 1 Всего: 1 |
Ребят, предположим у нас есть некий класс и в нем конструктор, куда передается строковый параметр FileName (Имя файла)
Возможно ли внутри реализации самого конструктора сделать проверку на существование файла и в зависимости от того, существует ли он - создавать экземпляр объекта или (если файла нет) выдать предупреждение и либо вовсе не создавать, либо разрушить объект?
Кстати в каком именно месте идет команда на выдачу объекту динамической памяти? Заранее спасибо. Это сообщение отредактировал(а) PsiMagistr - 1.6.2010, 19:21 -------------------- "Арфы нет? Возьмите бубен! Ребята, будем жить!" (с) "В бой идут одни старики" --- "ИЕ" - один из самых сумасшедших браузеров в нашей галактике. |
|||
|
||||
| kami |
|
||||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1806 Регистрация: 25.8.2007 Где: Санкт-Петербург Репутация: 22 Всего: 72 |
Нет. В самом конструкторе разрушать объект нельзя. Можно сделать "отложенное" удаление компонента/класса через PostMessage. В данном случае лучшим выходом будет проверка в основном коде на существование файла и после этого уже вызов/не-вызов конструктора. Например, сделать классовый метод, типа
Afair, перед(во время) вызова конструктора. Ибо в самом конструкторе уже доступны все поля и методы созданного объекта. |
||||
|
|||||
| Демо |
|
||||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1278 Регистрация: 3.11.2005 Репутация: 7 Всего: 50 |
Немного не так. Есть 2 метода. Один указал kami - использовать классовую функцию:
Второй метод - поднимать исключение в конструкторе. На примере того же класса:
При возникновении в конструкторе исключения будет немедленно вызван деструктор, а объект не будет создан. Во этом случае код в деструкторе нужно писать, учитывая, что в конструкторе может возникнуть исключение. -------------------- |
||||
|
|||||
| kami |
|
|||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1806 Регистрация: 25.8.2007 Где: Санкт-Петербург Репутация: 22 Всего: 72 |
||||
|
||||
| CodeMonkey |
|
|||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1839 Регистрация: 24.6.2008 Где: Россия, Тверь Репутация: 29 Всего: 89 |
TFileStream ведь так работает.
-------------------- Опытный программист на C++ легко решает любые не существующие в Паскале проблемы. |
|||
|
||||
| PsiMagistr |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 479 Регистрация: 31.12.2009 Репутация: 1 Всего: 1 |
СПА-СИ-БО ВСЕМ! 1). А как именно можно словить это исключение в деструкторе? Ну хотя бы примерно? (Просто я о классах исключений слышал, но не более того. Очень поверхностно.) 2) Что есть "классовая функция"? (Даже не слыхал о таком.) Ребята, когда-то я писал ролевую игру на VB. Несмотря на то что я бросил проект, не могу сказать, что он не удался, т.к. все заложенные функции работали исправно, работа с файлами тоже была. Можно было даже бои устраивать и опыт набирать. Но там все было реализовано на уровне процедурного программирования. Ну не считая компонентов брошенных на формы. )))) Теперь мне в голову стукнуло - зашить всю начинку вовнутрь класса Сущность и его производных (Персонаж-Монстр), создать объекты и пусть все свершается в них, чтобы больше с этой рутинной работой не колебаться хотя бы внутри кода основного модуля. P.S. Потратил 2 часа написал на Дельфи "Пятнашки" (головоломка такая). Код вышел стремный, от балды, но работает. Это сообщение отредактировал(а) PsiMagistr - 2.6.2010, 08:55 -------------------- "Арфы нет? Возьмите бубен! Ребята, будем жить!" (с) "В бой идут одни старики" --- "ИЕ" - один из самых сумасшедших браузеров в нашей галактике. |
|||
|
||||
| Демо |
|
||||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1278 Регистрация: 3.11.2005 Репутация: 7 Всего: 50 |
А зачем в деструкторе его отдавливать? Задача деструктора - освободить ресурсы и выполнить заключительные процедуры перед уничтожением.
Эту фразу надо понимать так: в деструкторе необходимо проверять, а действительно ли были в конструкторе выделены необходимые ресурсы. В большинстве случаев это простейшие проверки: if Assigned() и т.п. class function/procedure - специальный вид функций, которые могут выполняться без создания экземпляра класса, не имеют доступа к ссылке на экземпляр класса (Self). Пример приведён выше. -------------------- |
||||
|
|||||
| PsiMagistr |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 479 Регистрация: 31.12.2009 Репутация: 1 Всего: 1 |
Гм... Признаться не совсем понял. Ведь если ты сумел вызвать Free (деструктор) объекта, то значит сам объект уже был создан. Ведь он создается сразу при входе в конструктор. Раз объект создан - память под него выделена. Зачем же нужны проверки - была ли выделена память?
Можно ли проверить в деструкторе, выделенна ли в конструкторе память так: If self <> nil then либо, if Assigned(self) = true then Это сообщение отредактировал(а) PsiMagistr - 2.6.2010, 10:36 -------------------- "Арфы нет? Возьмите бубен! Ребята, будем жить!" (с) "В бой идут одни старики" --- "ИЕ" - один из самых сумасшедших браузеров в нашей галактике. |
|||
|
||||
| Демо |
|
|||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1278 Регистрация: 3.11.2005 Репутация: 7 Всего: 50 |
Проверять нужно не сам объект, а поля и ресурсы, выделение памяти для которых и создание происходит в конструкторе. Дома буду - набросаю пример. -------------------- |
|||
|
||||
| CodeMonkey |
|
|||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1839 Регистрация: 24.6.2008 Где: Россия, Тверь Репутация: 29 Всего: 89 |
PsiMagistr, есть хороший пример и я вам в него ткнул:
Как видите, конструктор проводит создание объекта, инициализацию полей и т.п. Если при этом он сталкивается с ошибкой (например, не может открыть файл), он выбрасывает исключение. При этом Delphi автоматически вызывает деструктор. Иными словами, цепочка вызовов при этом выглядит так: CreateInstance (выделение памяти для Self) -> Create -> исключение -> Destroy -> FreeInstance (удаление памяти для Self). Сравните это со штатной ситуацией: CreateInstance (выделение памяти для Self) -> Create, далее вы работаете с объектом, вызывая в конце работы Free, Free -> Destroy -> FreeInstance (удаление памяти для Self). Поскольку в случае возникновения ошибки конструктор выполняется не полностью, то деструктор должен быть готов к удалению частично-инициализированного объекта. Что означает, что не все поля в экземпляре будут заданы. В примере выше обратите внимание, как деструктор закрывает описатель файла только, если он был открыт (if FHandle <> INVALID_HANDLE_VALUE). -------------------- Опытный программист на C++ легко решает любые не существующие в Паскале проблемы. |
|||
|
||||
| PsiMagistr |
|
||||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 479 Регистрация: 31.12.2009 Репутация: 1 Всего: 1 |
CodeMonkey, благодарю.
Сижу, пробую, что то странное происходит. Но обо всем по порядку. Создал проект. Добавил новый модуль. В новый модуль подключил все заголовочные функции. Подключил сам модуль к модулю формы. Описание класса (раздел interface добавленного модуля.)
Реализация методов класса (Раздел implementation модуля)
Такое впечатление, что мой деструктор очищает не всю память... Это сообщение отредактировал(а) PsiMagistr - 2.6.2010, 15:11 -------------------- "Арфы нет? Возьмите бубен! Ребята, будем жить!" (с) "В бой идут одни старики" --- "ИЕ" - один из самых сумасшедших браузеров в нашей галактике. |
||||
|
|||||
| CodeMonkey |
|
|||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1839 Регистрация: 24.6.2008 Где: Россия, Тверь Репутация: 29 Всего: 89 |
Сыграем в игру (люблю я это дело)
Буратине дали три яблока. Сколько яблок у буратины? Думаете три? Ничего подобного. Никто же не сказал, сколько яблок было до того, как ему дали три. Мораль истории: инициализируйте переменные. Способны ли вы теперь с этой подсказкой найти объяснение видимому поведению? ;) -------------------- Опытный программист на C++ легко решает любые не существующие в Паскале проблемы. |
|||
|
||||
| PsiMagistr |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 479 Регистрация: 31.12.2009 Репутация: 1 Всего: 1 |
Благодарю, CodeMonkey. ))) Развивайте мысль. )))) О каких переменных идет речь в данном случае? Насколько я понимаю, все переменные какими мы обладаем вроде получили инициализацию, во всяком случае так считает компилятор.
Внешний указатель вроде только один. MyObject. переменная-поле внутри класса fName. А теперь Ваши соображения? ) -------------------- "Арфы нет? Возьмите бубен! Ребята, будем жить!" (с) "В бой идут одни старики" --- "ИЕ" - один из самых сумасшедших браузеров в нашей галактике. |
|||
|
||||
| CodeMonkey |
|
||||||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1839 Регистрация: 24.6.2008 Где: Россия, Тверь Репутация: 29 Всего: 89 |
Строка
Раскладывается на более простые действия так: - вызвать конструктор - ссылку, которую вернул конструктор, записать в переменную MyObject. Соответственно, если конструктор возбуждает исключение, то выполнение прерывается и запись чего-либо в MyObject не происходит. Откуда следует, что в MyObject остаётся то, что было в ней до вышеуказанной строчки - т.е. мусор. Очевидно, что вызов
Когда в MyObject лежит мусор, приводит к произвольному поведению. Это может быть нормальная работа, это может быть access violation - что угодно. P.S. Проверка
В деструкторе излишня - этим занимается Free. Уберите. -------------------- Опытный программист на C++ легко решает любые не существующие в Паскале проблемы. |
||||||
|
|||||||
| PsiMagistr |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 479 Регистрация: 31.12.2009 Репутация: 1 Всего: 1 |
Спасибо большое.
Точно. Вызывали мы объект. А он не вызвался (исключение). Что в осталось в указателе? А чушь полная... Неплохо было бы в деструкторе класса прописать чтобы указатель получал хотя бы Nil. Только конечная операция деструктора опять будет inherited Destroy и оно опять мусор зашлет в указатель... Вы пишите If Assigned(self) then в деструкторе лишняя? Вот тут я не могу понять, почему? Да во Free есть эта встроенная проверка. Но именно Free нигде не вызывается. До него дело не доходит, просто. Вызывается голый деструктор. А попытка вызвать Free в деструкторе: self.free; вместо inherited Destroy; просто приведет к тому, что Free сам по себе станет вызывать деструктор, а деструктор - Free. И так без конца. Это сообщение отредактировал(а) PsiMagistr - 3.6.2010, 13:12 -------------------- "Арфы нет? Возьмите бубен! Ребята, будем жить!" (с) "В бой идут одни старики" --- "ИЕ" - один из самых сумасшедших браузеров в нашей галактике. |
|||
|
||||
| Демо |
|
||||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1278 Регистрация: 3.11.2005 Репутация: 7 Всего: 50 |
Деструктор вызывается только для созданного объекта. т.е. Self существует по-определению. Далее - предка, для которого нужно было бы вызвать свой деструктор, нет.
Вместо всего этого достаточно destructor TMyClass.Destroy; begin ShowMessage('Сейчас вызову деструктор!'); //Даю сообщение и end; -------------------- |
||||
|
|||||
| PsiMagistr |
|
||||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 479 Регистрация: 31.12.2009 Репутация: 1 Всего: 1 |
Демо, благодарю.
Забавно. Я полагал, что предок всегда есть (TObject хотя бы). Правильно ли я вас понял, что невозможно вызвать деструктор для несуществующего объекта? Мне бы как-то попытаться сделать так, чтобы:
При отсутствии файла мне мало просто вызвать деструктор. Мне важно, чтобы в MyObject был nil. Но вот как его туда заслать? Ведь при исключении тут же вызывается деструктор, который разрушает все и в конечном итоге - мусор в MyObject. Или я не так понимаю? Это сообщение отредактировал(а) PsiMagistr - 3.6.2010, 16:50 -------------------- "Арфы нет? Возьмите бубен! Ребята, будем жить!" (с) "В бой идут одни старики" --- "ИЕ" - один из самых сумасшедших браузеров в нашей галактике. |
||||
|
|||||
| Mikel |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 882 Регистрация: 30.3.2002 Где: Саратов Репутация: нет Всего: 2 |
А почему бы не сделать что-н типа:
Вынести просто ту логику в инит... -------------------- ...so remember, it's better to burn out than to fade away |
|||
|
||||
| PsiMagistr |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 479 Регистрация: 31.12.2009 Репутация: 1 Всего: 1 |
Mikel, О, это интересная идея.
А что есть init? Как я понял свойство проверки инициализации? P.S. Я очень мало знаком с внутренней структурой объектов. К ООП приступил недавно. -------------------- "Арфы нет? Возьмите бубен! Ребята, будем жить!" (с) "В бой идут одни старики" --- "ИЕ" - один из самых сумасшедших браузеров в нашей галактике. |
|||
|
||||
| Mikel |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 882 Регистрация: 30.3.2002 Где: Саратов Репутация: нет Всего: 2 |
Initом я просто обозвал функцию в которую предлагаю тебе вынести всю логику из Create. В Create только создавать объект.
-------------------- ...so remember, it's better to burn out than to fade away |
|||
|
||||
| PsiMagistr |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 479 Регистрация: 31.12.2009 Репутация: 1 Всего: 1 |
Mikel, благодарю от души за участие. Понимаете суть моей задачи в чем... Я загорелся идеей фикс зашить в класс всю работу с файлами.
Т.е. Есть файл (или соотвествующая запись в нем) - конструктор загружает данные в поля и создает объект. Нет файла - нет объекта. А в объектном указателе в этом случае - Nil. Причем все это должно крутиться внутри класса. В этом весь смак. Обслужить все внешними проверками можно, но тогда нет особого смысла и в классе. Я хочу выжать максимум универсальности. -------------------- "Арфы нет? Возьмите бубен! Ребята, будем жить!" (с) "В бой идут одни старики" --- "ИЕ" - один из самых сумасшедших браузеров в нашей галактике. |
|||
|
||||
| Демо |
|
|||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1278 Регистрация: 3.11.2005 Репутация: 7 Всего: 50 |
Нет предка, для которого необходимо вызвать дополнительно деструктор. Хотя я всегда использую inherited Destroy в своём коде. Это позволяет никогда не забывать вызывать деструктор предка. CodeMonkey уже писал тебе о том, что перед созданием объекта переменную нужно проинициализировать. т.е.
В случае возникновения исключения значение MyObject не изменится. Не путай псевдопеременную Self с обычной переменной-ссылкой на объект. Это сообщение отредактировал(а) Демо - 3.6.2010, 17:16 -------------------- |
|||
|
||||
| PsiMagistr |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 479 Регистрация: 31.12.2009 Репутация: 1 Всего: 1 |
Демо, дружище. Именно так я и пытался писать. Более того я писал проверки, чтобы отследить:
Это сообщение отредактировал(а) PsiMagistr - 3.6.2010, 17:23 -------------------- "Арфы нет? Возьмите бубен! Ребята, будем жить!" (с) "В бой идут одни старики" --- "ИЕ" - один из самых сумасшедших браузеров в нашей галактике. |
|||
|
||||
| Демо |
|
|||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1278 Регистрация: 3.11.2005 Репутация: 7 Всего: 50 |
А каким образом ты можешь дождаться сообщения, если на строке MyObJect:=TMyClass.Create('Проба.txt'); у тебя возникает исключение, и следующие строки не выполняются?
-------------------- |
|||
|
||||
| PsiMagistr |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 479 Регистрация: 31.12.2009 Репутация: 1 Всего: 1 |
А вот тут я совсем не понял чего-то. Допустим возникает исключение. И что? Оно же в конструкторе возникает. Ну конструктор, ясное дело, обваливается. Но проверка на nill не в конструкторе, она внешняя, из программы, в обработчике кнопки. По идее должен был быть переход к след шагу, неужели же обваливается вся процедура, где этот злосчастный конструктор вызван? Но тогда получается что из за исключения в конструкторе вся программа клеит ласты)))
Это сообщение отредактировал(а) PsiMagistr - 3.6.2010, 17:46 -------------------- "Арфы нет? Возьмите бубен! Ребята, будем жить!" (с) "В бой идут одни старики" --- "ИЕ" - один из самых сумасшедших браузеров в нашей галактике. |
|||
|
||||
| bems |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 3400 Регистрация: 5.1.2006 Репутация: 18 Всего: 88 |
Деструктор нужно писать так всегда. Без исключений.
После выполнения деструктора исключение остаётся необработанным, и поднимается вверх по стеку вызовов (с выполнением всех секций finally), до ближайшего по стеку обработчика (это может быть except или обработчик исключений из TApplication, который просто выводит сообщение) Это сообщение отредактировал(а) bems - 3.6.2010, 18:01 -------------------- Обижено школьников: 8 |
|||
|
||||
| PsiMagistr |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 479 Регистрация: 31.12.2009 Репутация: 1 Всего: 1 |
bems, и что вы предлагаете? Вот у меня исключение в конструкторе вызывается и весь обработчик кнопки, где я этот конструктор призвал обваливается.
Это сообщение отредактировал(а) PsiMagistr - 3.6.2010, 18:31 -------------------- "Арфы нет? Возьмите бубен! Ребята, будем жить!" (с) "В бой идут одни старики" --- "ИЕ" - один из самых сумасшедших браузеров в нашей галактике. |
|||
|
||||
| bems |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 3400 Регистрация: 5.1.2006 Репутация: 18 Всего: 88 |
PsiMagistr, да, обваливается. Ты видишь в этом что-то плохое?
Если ты знаешь что делать в случае отсутствия файла, то пиши секцию except Это сообщение отредактировал(а) bems - 3.6.2010, 18:32 -------------------- Обижено школьников: 8 |
|||
|
||||
| Демо |
|
||||||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1278 Регистрация: 3.11.2005 Репутация: 7 Всего: 50 |
Это ещё почему?
Ты не умеешь обрабатывать исключения?
-------------------- |
||||||
|
|||||||
| PsiMagistr |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 479 Регистрация: 31.12.2009 Репутация: 1 Всего: 1 |
Демо, нет. НЕ умею. Честно. Я только к дельфи приступил. С книгой сижу.
Вот реализация конструктора:
Вот только как его обработать, чтоб после выполнения исключения обработчик, где будет вызываться конструктор не обваливался? В случае отсутствия файла - присвоить указателю на объект nil. Но поскольку я его и так инициализировал с nil а меняться он не должен. то в случае отсутствия можно ничего не делать. Поскольку деструктор возникнет автоматом. Это сообщение отредактировал(а) PsiMagistr - 3.6.2010, 19:16 -------------------- "Арфы нет? Возьмите бубен! Ребята, будем жить!" (с) "В бой идут одни старики" --- "ИЕ" - один из самых сумасшедших браузеров в нашей галактике. |
|||
|
||||
| Демо |
|
||||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1278 Регистрация: 3.11.2005 Репутация: 7 Всего: 50 |
-------------------- |
||||
|
|||||
| CodeMonkey |
|
||||||||||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1839 Регистрация: 24.6.2008 Где: Россия, Тверь Репутация: 29 Всего: 89 |
Этим должен заниматься не класс. Потому что переменной может вообще не быть. Понимаете, класс работает со своими данными, с тем, что внутри. Переменная - это не его данные, она снаружи, и вообще никак не связана с классом. Но если сильно охота, то можно - в качестве примера посмотрите реализацию Application.CreateForm (вызов смотреть в DPR-файле, а реализацию - в Forms.pas). Но делать так без веских причин я бы не стал.
Потому что Self = nil в деструкторе - это глюк (почему? уже сказал Demo: при вызове из конструктора Self гарантировано не-nil, а при внешнем вызове вы вызываете Free; хотя формально вы вполне можете вызывать TForm(nil).Destroy). Такого не должно быть. А раз не должно быть, то вылететь с access violation - вполне нормальный вариант. Можете не засорять исходники лишними проверками. Только надо понимать, что "достаточно" <> "нужно так делать". Верно.
Сделать можно что угодно:
Но тогда вы сами себе буратино.
Рекомендую почитать. Добавлено через 5 минут и 22 секунды Согласен с bems-ом по поводу деструктора. По той простой причине, что пустой конструктор - это деталь реализации, а не стандарт ООП языка. Вот выйдет Fulcrum - откуда вы знаете, может там в деструкторе что-то будет, чтобы сгладить косяки платформы? Вы уверены, что в FreePascal (подставьте сюда любой компилятор Паскаля, с которым вы не знакомы) деструктор тоже пустой? Но это не главное. А главное в том, что класс может быть изменён в процессе рефакторинга позже. В том числе, он может сменить предка. Вызов унаследованных конструкторов и деструкторов всегда - это простое правило, которое поможет вам избежать потенциальных проблем. -------------------- Опытный программист на C++ легко решает любые не существующие в Паскале проблемы. |
||||||||||
|
|||||||||||
| Демо |
|
|||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1278 Регистрация: 3.11.2005 Репутация: 7 Всего: 50 |
Да согласен я-) Смысл фразы в том, что нужно всегда знать, что делаешь. Если я знаю в данный момент, что в TObject мне ничего не нужно освобождать, то с полным сознанием и уверенностью могу не вызывать родительский деструктор, учитывая, что другоим колмпилятором я не буду пользоваться... -------------------- |
|||
|
||||
| bems |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 3400 Регистрация: 5.1.2006 Репутация: 18 Всего: 88 |
Потому что очень трудно следить за каждым конструктором на предмет озможности исключений. Правильнее считать что исключение может возникнуть в любом месте любого конструктора (собственно это не далеко от истины). Если моих слов не достаточно то вот:
А твой пример ни к селу ни к городу. Ясно, что если деструктор ничего не делает, то и проверять нечего (даже если бы в конструкторе TObject и могло возникнуть исключение) Добавлено через 12 минут и 42 секунды что-то меня не поняли. Я говорил не о вызове унаследованного деструктора, а о том, чтобы всегда писать деструктор так, чтобы он мог разрушать недосозданный объект -------------------- Обижено школьников: 8 |
|||
|
||||
| Демо |
|
|||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1278 Регистрация: 3.11.2005 Репутация: 7 Всего: 50 |
Действительно не поняли. Я-то говорил именно об обязательности вызова родительского деструктора. -------------------- |
|||
|
||||
| bems |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 3400 Регистрация: 5.1.2006 Репутация: 18 Всего: 88 |
Даже если это нехватка памяти или Assert? -------------------- Обижено школьников: 8 |
|||
|
||||
| Демо |
|
|||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1278 Регистрация: 3.11.2005 Репутация: 7 Всего: 50 |
Ну если нехватка памяти, то вряд ли можно что-то ещё сделать. А работу с Assert надо заранее проектировать-) -------------------- |
|||
|
||||
| PsiMagistr |
|
||||||||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 479 Регистрация: 31.12.2009 Репутация: 1 Всего: 1 |
Ребята, благодарю всех. Огромное СПС! Сейчас читаю информацию предоставленную, CodeMonkey :
Итак как я сделал: Реализация конструктора:
Реализация деструктора:
А в коде кнопки:
Запускать это из самой среды бесполезно - Дельфи споткнется в конструкторе. Поэтому компилирую файл. Все как будто получается. И деструктор вызывается. Но таблички:
Это сообщение отредактировал(а) PsiMagistr - 4.6.2010, 12:41 -------------------- "Арфы нет? Возьмите бубен! Ребята, будем жить!" (с) "В бой идут одни старики" --- "ИЕ" - один из самых сумасшедших браузеров в нашей галактике. |
||||||||
|
|||||||||
| CodeMonkey |
|
||||||||||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1839 Регистрация: 24.6.2008 Где: Россия, Тверь Репутация: 29 Всего: 89 |
= True - излишне. Это всё равно, что спрашивать "если да равно да то" или "включен ли компьютер" (если бы компьютер был бы выключен, программа не смогла бы задать этот вопрос). Надо:
Это уведомление отладчика сделано исключительно для вашего удобства, чтобы вы могли исследовать ситуацию, приводящую к ошибке, прямо на месте. Если вы не хотите этого делать - просто жмите Continue (в новых Delphi) или Run/Run (в старых). Вы также можете отключить эти уведомления в настройках среды, но я бы не стал этого делать - это исключительно полезный механизм. Вы же сами её заблокировали блоком except. Далее, проверять в except MyObject на nil - излишне, т.к. если вы попали в блок except, то только потому, что создание объекта обвалилось. Это всё равно, что проверять Self <> nil в деструкторе. Поэтому:
А вот и табличка:
Или:
В общем, миллион способов. А выбор зависит от того, зачем это надо, и что вы будете делать дальше. И я бы, на вашем месте, рассказал бы побольше про это. -------------------- Опытный программист на C++ легко решает любые не существующие в Паскале проблемы. |
||||||||||
|
|||||||||||
| PsiMagistr |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 479 Регистрация: 31.12.2009 Репутация: 1 Всего: 1 |
Я попробую в двух словах. Решил писать ролевую игру. Когда то давно писал на VB первый экземпляр. Получилось. Правда реализовывать ООП я не стал, обошелся процедурным программированием.
Основная текущая задача - зашить в класс работу с файлами. Вот например файл персонажа. Изначально там служебная информация, недоступная игроку. (параметры умолчания). Например: Жизнь-100 Интеллект-50 Ловкость=30 И .т.д. Что это значит. Когда мы создаем нового персонажа, конструктор объекта "Персонаж" читает служебную запись файла, считывает переменные умолчания и на основании этого строит вторую запись - это уже реальный персонаж, доступ к которому имеет игрок. В классе я пытаюсь охватить все возможные нюансы работы с файлами. Например обращение из основной программы: MyObject.Lovkost:=30; к свойству "Ловкость", будет означать не только присвоение, но и запись соответствующей информации в файл. Это сообщение отредактировал(а) PsiMagistr - 4.6.2010, 13:04 -------------------- "Арфы нет? Возьмите бубен! Ребята, будем жить!" (с) "В бой идут одни старики" --- "ИЕ" - один из самых сумасшедших браузеров в нашей галактике. |
|||
|
||||
| CodeMonkey |
|
|||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1839 Регистрация: 24.6.2008 Где: Россия, Тверь Репутация: 29 Всего: 89 |
Так, а теперь, внимание, вопрос (С)
Положим вы создаёте персонажа из файла TMyObject.Create('SavedGame01.dat'); Положим файл не найден, заблокирован антивирусом или тупо повреждён - вы выбрасываете исключение, отлично. Но. Дальше-то вы что делаете? А дальше вы обрабатываете эту ошибку, показывая мессагу, производя откат или что там ещё придумаете. Но при этом вы не обращаетесь к MyObject. Почему? Потому что он был не создан. Зачем вам обращаться к несуществующему объекту? Я имею ввиду, что вы просто не доходите до этого кода, например:
Если создание объекта проваливается, то до использования объекта ниже вы не доходите. Именно поэтому я сказал, что ваши попытки сделать MyObJect := nil выглядят очень подозрительно. Как, в целом, узнают, что MyObJect <> nil? По месту выполнения кода. -------------------- Опытный программист на C++ легко решает любые не существующие в Паскале проблемы. |
|||
|
||||
| PsiMagistr |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 479 Регистрация: 31.12.2009 Репутация: 1 Всего: 1 |
CodeMonkey, благодарен безмерно. попробую Вам объяснить в чем штука со всеми нюансами.
Итак, у нас есть файл записей (record). Первая запись данного файла - это служебная информация прототипа. Доступ игрока к ней закрыт. Остальные записи в файле это параметры реальных персонажей. В классе будут ДВА конструктора CreateOpen и CreateNew. Если игрок будет открывать уже созданного персонажа то вызываем конструктор CreateOpen, куда передадим лог-пасс. CreateOpen будет проверять существование файла. Если нет, генерируем сообщение "Не хватает служебных ресурсов". Обваливаем конструктор исключением и закрывем программу. Если файл есть, обходим его ночным дозором , поочередно забираем в переменные-поля параметры каждой записи и сравниваем их лог-пассы с лог-пассом введенным пользователем. Если совпадает то: Грузим конструктором туда все данные из найденной записи. И создаем, наконец, объект. А если не совпадает: Генерируем сообщение "Неверный лог-пасс", обрушиваем конструктор и не создаем объект. Введет пользователь новый лог-пасс, нажмет на кнопочку и... Будет новая попытка создания объекта. Второй конструктор CreatNew занимается другим. Он Проверяет, существует ли файл. Если да, то берет служебную первую запись. Грузит значения в переменные. Берет лог-пасс введенный пользователем снова грузит в переменные (подменяя там формальные значения-умолчания взятые из служебной записи). и наконец создает вторую запись. Вторая запись - действительный персонаж. К нему впоследствии обращается игрок. Это сообщение отредактировал(а) PsiMagistr - 4.6.2010, 15:01 -------------------- "Арфы нет? Возьмите бубен! Ребята, будем жить!" (с) "В бой идут одни старики" --- "ИЕ" - один из самых сумасшедших браузеров в нашей галактике. |
|||
|
||||
| CodeMonkey |
|
|||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1839 Регистрация: 24.6.2008 Где: Россия, Тверь Репутация: 29 Всего: 89 |
Ээээ.... ну? Что-то я не понял, что вы хотели сказать.
Зачем тогда вам в этом сценарии обнуление переменной MyObject при неудаче? Если в обоих случаях при исключении вы просто игнорируете переменную и не обращаетесь к ней? P.S. Конструктор не обязательно должен начинаться с Create. Удобно создать два конструктора так:
Ибо вызовы TMyObject.Create(...) и TMyObject.Open(...) смотрятся как-то "читабельнее", нежели TMyObject.CreateNew(...) и TMyObject.CreateOpen(...). Это сообщение отредактировал(а) CodeMonkey - 4.6.2010, 14:48 -------------------- Опытный программист на C++ легко решает любые не существующие в Паскале проблемы. |
|||
|
||||
| PsiMagistr |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 479 Регистрация: 31.12.2009 Репутация: 1 Всего: 1 |
CodeMonkey, свершенно верно. В реальности в случае обрушения в конструкторе в указателе может остаться даже "мусор умолчания" (хотя по моему по умолчанию указатель равен - nil). Объекта то все равно нет и делать нам нечего.
Но мусор для меня нежелателен, хочу чтоб все под контролем было . Это сообщение отредактировал(а) PsiMagistr - 4.6.2010, 14:58 -------------------- "Арфы нет? Возьмите бубен! Ребята, будем жить!" (с) "В бой идут одни старики" --- "ИЕ" - один из самых сумасшедших браузеров в нашей галактике. |
|||
|
||||
| PsiMagistr |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 479 Регистрация: 31.12.2009 Репутация: 1 Всего: 1 |
Вот еще какая тонкая штука, нюансик.
ДАННЫЙ ВОПРОС СНИМАЕТСЯ. Я голова садовая, совсем забыл, что Free контролирует указатель и только в случае указатель <> Nil вызывает деструктор. Это сообщение отредактировал(а) bems - 4.6.2010, 17:49 -------------------- "Арфы нет? Возьмите бубен! Ребята, будем жить!" (с) "В бой идут одни старики" --- "ИЕ" - один из самых сумасшедших браузеров в нашей галактике. |
|||
|
||||
| CodeMonkey |
|
||||||||||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1839 Регистрация: 24.6.2008 Где: Россия, Тверь Репутация: 29 Всего: 89 |
Так, давайте ещё раз. Есть два сценария использования любого объекта. Первый - локально:
Как видите, ничего страшного в том, что у вас в MyObject видит мусор нет. Потому что если возникнет исключение, вы вообще выйдете из процедуры, и сама переменная даже исчезнет. Сценарий 2: глобально Здесь MyObject - глобальная переменная или поле объекта (например, формы)
Как видите, и здесь не надо никуда nil присваивать. Хотя вы обращаетесь к переменной после исключения, но там уже не мусор, а nil, потому что поля объекта и глобальные переменные не содержат мусор, а содержат нули. P.S. Вместо
Лучше делать
-------------------- Опытный программист на C++ легко решает любые не существующие в Паскале проблемы. |
||||||||||
|
|||||||||||
| PsiMagistr |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 479 Регистрация: 31.12.2009 Репутация: 1 Всего: 1 |
Благодарю сердечно, CodeMonkey.
-------------------- "Арфы нет? Возьмите бубен! Ребята, будем жить!" (с) "В бой идут одни старики" --- "ИЕ" - один из самых сумасшедших браузеров в нашей галактике. |
|||
|
||||
| PsiMagistr |
|
||||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 479 Регистрация: 31.12.2009 Репутация: 1 Всего: 1 |
Скоро буду готов к описанию классов. Возник следующий нюанс:
Все переменные класса (поля), должны сохраняться в файле записей (record). Следовательно объявить их просто полями как:
Представляется невозможным, так как, все поля должны сохраняться в одной записи (файла). Можно решить дело так:
Но это представляется мне тоже довольно неудобным. Тем более что класса в программе три (базовый класс Сущность и его наследники Персонаж и Монстр). И все они отличаются количеством полей. При работе с файлами есть ли разница используем ли FileStream или стандартные команды: (Write Reset)? Это сообщение отредактировал(а) PsiMagistr - 8.6.2010, 12:48 -------------------- "Арфы нет? Возьмите бубен! Ребята, будем жить!" (с) "В бой идут одни старики" --- "ИЕ" - один из самых сумасшедших браузеров в нашей галактике. |
||||
|
|||||
| CodeMonkey |
|
|||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1839 Регистрация: 24.6.2008 Где: Россия, Тверь Репутация: 29 Всего: 89 |
Вообще-то, для классов нет нужды использовать записи. Вы можете сделать поля, которые хотите сохранять, published и сохранять в поток (TStream, в частности - TFileStream) обычными средствами. Класс при этом должен наследоваться от TPersistent.
-------------------- Опытный программист на C++ легко решает любые не существующие в Паскале проблемы. |
|||
|
||||
| PsiMagistr |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 479 Регистрация: 31.12.2009 Репутация: 1 Всего: 1 |
Да? Это интересно. А поподробней, если можно? Как сохранить через объект класса TFileStream запись, представляю. А вот поля класса...
Наткнулся на умную статью: http://forum.vingrad.ru/topic-94245/view-all.html Но к сожалению понял мало что... Это сообщение отредактировал(а) PsiMagistr - 8.6.2010, 14:28 -------------------- "Арфы нет? Возьмите бубен! Ребята, будем жить!" (с) "В бой идут одни старики" --- "ИЕ" - один из самых сумасшедших браузеров в нашей галактике. |
|||
|
||||
| Rennigth |
|
|||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 1708 Регистрация: 21.6.2004 Где: Moscow Репутация: 15 Всего: 76 |
А что конкретно не понятно? Вроде там все с примерами... Это сообщение отредактировал(а) Rennigth - 8.6.2010, 14:43 -------------------- (* Honesta mors turpi vita potior *) |
|||
|
||||
| PsiMagistr |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 479 Регистрация: 31.12.2009 Репутация: 1 Всего: 1 |
Пример хорош, но... Слишком много тонкостей.
Цитата: "модуль для сохранения и чтения объектов". (Почему именно объектов, а не данных полей класса? Что значит сохранить объект? Голова кругом от научной терминологии) Что есть: TWriter, TReader. Как они работают? И подробней о теории потоков (TStream). Кроме того у меня должен быть именно файл записей. И каждая запись в файле - индивидуальный набор параметров. Это сообщение отредактировал(а) PsiMagistr - 8.6.2010, 15:41 -------------------- "Арфы нет? Возьмите бубен! Ребята, будем жить!" (с) "В бой идут одни старики" --- "ИЕ" - один из самых сумасшедших браузеров в нашей галактике. |
|||
|
||||
| PsiMagistr |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 479 Регистрация: 31.12.2009 Репутация: 1 Всего: 1 |
Смотрю статью. Ковыряюсь в коде примера. Что интересно: там процедуры записи-чтения объекта (полей) являются внешними. А мне бы их в класс встроить. Попробую завтра эксперимент сделать.
Это сообщение отредактировал(а) PsiMagistr - 8.6.2010, 18:18 -------------------- "Арфы нет? Возьмите бубен! Ребята, будем жить!" (с) "В бой идут одни старики" --- "ИЕ" - один из самых сумасшедших браузеров в нашей галактике. |
|||
|
||||
![]()
|
| Правила форума "Delphi: Для новичков" | |
|
|
Запрещается! 1. Публиковать ссылки на вскрытые компоненты 2. Обсуждать взлом компонентов и делиться вскрытыми компонентами
Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Snowy, MetalFan, bems, Poseidon, Rrader. |
| 0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей) | |
| 0 Пользователей: | |
| « Предыдущая тема | Delphi: Для новичков | Следующая тема » |
|
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |