Модераторы: Snowy, MetalFan, bems, Poseidon

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Вызов деструктора внутри конструктора 
:(
    Опции темы
PsiMagistr
Дата 1.6.2010, 18:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 479
Регистрация: 31.12.2009

Репутация: 1
Всего: 1



Ребят, предположим у нас есть некий класс и в нем конструктор, куда передается строковый параметр FileName (Имя файла)

Возможно ли внутри реализации самого конструктора сделать проверку на существование файла и в зависимости от того, существует ли он - создавать экземпляр объекта или (если файла нет) выдать предупреждение и либо вовсе не создавать, либо разрушить объект?





Код


MyClass.Create(Filename:String);
Begin
Inherited Create;

If FileExist(FileName) then

................................... //Читаем файл.
....................................//Заполняем поля класса параметрами из файла.

else Иначе

Begin
ShowMessage('Файла нет!'); //Сообщение то появится...
self.Free; //А вот будет ли работать разрушение. Может объект еще создаться не успел? Может лучше просто покинуть метод  через Exit?
End;

End; //Внимание! Есть большие-большие сомнения, что этот код будет работать.




//Где то там в коде:

var MyObject : TMyClass; //Объявили переменную-указатель класса.

//Пытаемся создать объект:

MyObject := TMyClass.Create('Мой файл.txt'); Если файл существует, то создаем экземпляр, если нет -  даем предупреждение.



Кстати в каком именно месте идет команда на выдачу объекту динамической памяти? Заранее спасибо. 



Это сообщение отредактировал(а) PsiMagistr - 1.6.2010, 19:21


--------------------
"Арфы нет? Возьмите бубен!

Ребята, будем жить!"

 (с) "В бой идут одни старики"

---

"ИЕ" - один из самых сумасшедших браузеров в нашей галактике.
PM MAIL   Вверх
kami
Дата 1.6.2010, 19:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1806
Регистрация: 25.8.2007
Где: Санкт-Петербург

Репутация: 22
Всего: 72



Цитата(PsiMagistr @  1.6.2010,  18:07 Найти цитируемый пост)
Возможно ли внутри реализации самого конструктора сделать проверку на существование файла и в зависимости от того, существует ли он - создавать экземпляр объекта или (если файла нет) выдать предупреждение и либо вовсе не создавать, либо разрушить объект?

Нет. В самом конструкторе разрушать объект нельзя. Можно сделать "отложенное" удаление компонента/класса через PostMessage.
В данном случае лучшим выходом будет проверка в основном коде на существование файла и после этого уже вызов/не-вызов конструктора. Например, сделать классовый метод, типа
Код

class function CanCreate(params:...):boolean

Цитата(PsiMagistr @  1.6.2010,  18:07 Найти цитируемый пост)
Кстати в каком именно месте идет команда на выдачу объекту динамической памяти?

Afair, перед(во время) вызова конструктора. Ибо в самом конструкторе уже доступны все поля и методы созданного объекта.
PM MAIL WWW   Вверх
Демо
Дата 1.6.2010, 20:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1278
Регистрация: 3.11.2005

Репутация: 7
Всего: 50



Цитата(kami @  1.6.2010,  19:53 Найти цитируемый пост)
Нет. В самом конструкторе разрушать объект нельзя. 


Немного не так.

Цитата(PsiMagistr @  1.6.2010,  18:07 Найти цитируемый пост)
Возможно ли внутри реализации самого конструктора сделать проверку на существование файла и в зависимости от того, существует ли он - создавать экземпляр объекта или (если файла нет) выдать предупреждение и либо вовсе не создавать, либо разрушить объект?


Есть 2 метода. 
Один указал kami - использовать классовую функцию:

Код

TMyClass=class
public
  constructor Create(const FilePath: String);
  class function CreateMyClass(const FilePath: String): TMyCLass;
end;

class function CreateMyClass(const FilePath: String): TMyCLass;
begin
  Result := nil;
  if FileExists(FilePath) then Result := TMyClass.Create(FilePath);
end;


Второй метод - поднимать исключение в конструкторе.
На примере того же класса:

Код

TMyClass=class
public
  constructor Create(const FilePath: String);
//  class function CreateMyClass(const FilePath: String): TMyCLass;
end;

constructor TMyClass.Create(const FilePath: String);
begin
  if not FileExists(FilePath) then raise Exception.Create('File not exists');
//...
end;


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


--------------------
    
PM MAIL ICQ Skype   Вверх
kami
Дата 1.6.2010, 21:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1806
Регистрация: 25.8.2007
Где: Санкт-Петербург

Репутация: 22
Всего: 72



Цитата(Демо @  1.6.2010,  20:59 Найти цитируемый пост)
При возникновении в конструкторе исключения будет немедленно вызван деструктор, а объект не будет создан.

Ай-я... а ведь точно!
Спасибо, открыл глаза smile
PM MAIL WWW   Вверх
CodeMonkey
Дата 1.6.2010, 22:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1839
Регистрация: 24.6.2008
Где: Россия, Тверь

Репутация: 29
Всего: 89



TFileStream ведь так работает.


--------------------
Опытный программист на C++ легко решает любые не существующие в Паскале проблемы.
PM MAIL WWW ICQ Skype GTalk Jabber   Вверх
PsiMagistr
Дата 2.6.2010, 08:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 479
Регистрация: 31.12.2009

Репутация: 1
Всего: 1



СПА-СИ-БО ВСЕМ!



Цитата(Демо @  1.6.2010,  20:59 Найти цитируемый пост)
При возникновении в конструкторе исключения будет немедленно вызван деструктор, а объект не будет создан.
Во этом случае код в деструкторе нужно писать, учитывая, что в конструкторе может возникнуть исключение. 


1). А как именно можно словить это исключение в деструкторе? Ну хотя бы примерно? (Просто я о классах исключений слышал, но не более того. Очень поверхностно.)

2) Что есть "классовая функция"? (Даже не слыхал о таком.)



Ребята, когда-то я писал ролевую игру на VB. Несмотря на  то что я бросил проект, не могу сказать, что он не удался, т.к. все заложенные функции работали исправно, работа с файлами тоже была. Можно было даже бои устраивать и опыт набирать. Но там все было реализовано на уровне процедурного программирования. Ну не считая компонентов брошенных на формы. ))))

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

P.S. Потратил 2 часа написал на Дельфи "Пятнашки" (головоломка такая). Код вышел стремный, от балды, но работает.






Это сообщение отредактировал(а) PsiMagistr - 2.6.2010, 08:55


--------------------
"Арфы нет? Возьмите бубен!

Ребята, будем жить!"

 (с) "В бой идут одни старики"

---

"ИЕ" - один из самых сумасшедших браузеров в нашей галактике.
PM MAIL   Вверх
Демо
Дата 2.6.2010, 09:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1278
Регистрация: 3.11.2005

Репутация: 7
Всего: 50



Цитата(PsiMagistr @  2.6.2010,  08:53 Найти цитируемый пост)
1). А как именно можно словить это исключение в деструкторе? Ну хотя бы примерно? (Просто я о классах исключений слышал, но не более того. Очень поверхностно.)


А зачем в деструкторе его отдавливать?
Задача деструктора - освободить ресурсы и выполнить заключительные процедуры перед уничтожением.


Цитата(Демо @  1.6.2010,  20:59 Найти цитируемый пост)
Во этом случае код в деструкторе нужно писать, учитывая, что в конструкторе может возникнуть исключение.


Эту фразу надо понимать так: 

в деструкторе необходимо проверять, а действительно ли были в конструкторе выделены необходимые ресурсы.
В большинстве случаев это простейшие проверки: if Assigned() и т.п.

Цитата(PsiMagistr @  2.6.2010,  08:53 Найти цитируемый пост)
2) Что есть "классовая функция"? (Даже не слыхал о таком.)


class function/procedure - специальный вид функций, которые могут выполняться без создания экземпляра класса, не имеют доступа к ссылке на экземпляр класса (Self).

Пример приведён выше.


--------------------
    
PM MAIL ICQ Skype   Вверх
PsiMagistr
Дата 2.6.2010, 10:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 479
Регистрация: 31.12.2009

Репутация: 1
Всего: 1



Гм... Признаться не совсем понял. Ведь если ты сумел вызвать Free (деструктор) объекта, то значит сам объект уже был создан. Ведь он создается сразу при входе в конструктор.  Раз объект создан - память под него выделена. Зачем же нужны проверки - была ли выделена память?

Можно ли проверить в деструкторе, выделенна ли в конструкторе память так:

 If self <> nil then либо,

 if Assigned(self) = true then



Это сообщение отредактировал(а) PsiMagistr - 2.6.2010, 10:36


--------------------
"Арфы нет? Возьмите бубен!

Ребята, будем жить!"

 (с) "В бой идут одни старики"

---

"ИЕ" - один из самых сумасшедших браузеров в нашей галактике.
PM MAIL   Вверх
Демо
Дата 2.6.2010, 11:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1278
Регистрация: 3.11.2005

Репутация: 7
Всего: 50



Цитата(PsiMagistr @  2.6.2010,  10:29 Найти цитируемый пост)
Гм... Признаться не совсем понял. Ведь если ты сумел вызвать Free (деструктор) объекта, то значит сам объект уже был создан. Ведь он создается сразу при входе в конструктор.  Раз объект создан - память под него выделена. Зачем же нужны проверки - была ли выделена память?


Проверять нужно не сам объект, а поля и ресурсы, выделение памяти для которых и создание происходит в конструкторе.
Дома буду - набросаю пример.


--------------------
    
PM MAIL ICQ Skype   Вверх
CodeMonkey
Дата 2.6.2010, 13:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1839
Регистрация: 24.6.2008
Где: Россия, Тверь

Репутация: 29
Всего: 89



PsiMagistr, есть хороший пример и я вам в него ткнул:

Код
constructor TFileStream.Create(const AFileName: string; Mode: Word; Rights: Cardinal);
var
  LShareMode: Word;
begin
  if (Mode and fmCreate = fmCreate) then
  begin
    LShareMode := Mode and $FF;
    if LShareMode = $FF then
      LShareMode := fmShareExclusive; // For compat in case $FFFF passed as Mode
    inherited Create(FileCreate(AFileName, LShareMode, Rights));
    if FHandle = INVALID_HANDLE_VALUE then
      raise EFCreateError.CreateResFmt(@SFCreateErrorEx, [ExpandFileName(AFileName), SysErrorMessage(GetLastError)]);
  end
  else
  begin
    inherited Create(FileOpen(AFileName, Mode));
    if FHandle = INVALID_HANDLE_VALUE then
      raise EFOpenError.CreateResFmt(@SFOpenErrorEx, [ExpandFileName(AFileName), SysErrorMessage(GetLastError)]);
  end;
  FFileName := AFileName;
end;

destructor TFileStream.Destroy;
begin
  if FHandle <> INVALID_HANDLE_VALUE then
    FileClose(FHandle);
  inherited Destroy;
end;


Как видите, конструктор проводит создание объекта, инициализацию полей и т.п. Если при этом он сталкивается с ошибкой (например, не может открыть файл), он выбрасывает исключение. При этом Delphi автоматически вызывает деструктор. Иными словами, цепочка вызовов при этом выглядит так: 

CreateInstance (выделение памяти для Self) -> Create -> исключение -> Destroy -> FreeInstance (удаление памяти для Self). 

Сравните это со штатной ситуацией: 

CreateInstance (выделение памяти для Self) -> Create, далее вы работаете с объектом, вызывая в конце работы Free, Free -> Destroy -> FreeInstance (удаление памяти для Self).

Поскольку в случае возникновения ошибки конструктор выполняется не полностью, то деструктор должен быть готов к удалению частично-инициализированного объекта. Что означает, что не все поля в экземпляре будут заданы. В примере выше обратите внимание, как деструктор закрывает описатель файла только, если он был открыт (if FHandle <> INVALID_HANDLE_VALUE).


--------------------
Опытный программист на C++ легко решает любые не существующие в Паскале проблемы.
PM MAIL WWW ICQ Skype GTalk Jabber   Вверх
PsiMagistr
Дата 2.6.2010, 14:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 479
Регистрация: 31.12.2009

Репутация: 1
Всего: 1



CodeMonkey, благодарю.

Сижу, пробую, что то странное происходит. Но обо всем по порядку.

Создал проект.  Добавил новый модуль. В новый модуль подключил все заголовочные функции. Подключил сам модуль к модулю формы.

Описание класса (раздел interface добавленного модуля.)

Код

unit Unit2;

interface

type TMyClass = class //Начало описания класса
fName:String; //Одно общедоступное поле.
constructor Create(FileName:String); //Конструктор со строковым параметром (Имя файла) внутри.
Destructor Destroy; override; //Деструктор
end;


Реализация методов класса (Раздел implementation  модуля)

Код

constructor TMyClass.Create(FileName:String);
begin
inherited Create; //Вызов конструктора предка.
if FileExists(ExtractFilePath(Application.ExeName)+FileName) = true then //Если файл существует то:

begin
Fname := 'Значение по умолчанию';  //Задаем значение полю FName  и
ShowMessage('Файл есть!'); // Выводим сообщение
end

Else raise Exception.Create('Файла нет!'); Вызываем исключение, а значит деструктор.
end;


Destructor TMyClass.Destroy; Реализация деструктора.
Begin

If Assigned(self) then //Если указатель не равен nil связан с объектом то:
begin
ShowMessage('Сейчас вызову деструктор!'); //Даю сообщение и
Inherited Destroy; //Вызов деструктора предка, освобождение памяти.
end;

end;



На форму добавляю кнопку, пишу в разделе объявление глобальных переменных указатель класса:

Var  MyObject : TMyClass;

//В обработчике щелчка на кнопку:

MyObJect:=TMyClass.Create('Файл.txt'); //Рождение объекта. А файла нет. Должен сработать деструктор.


MyObject.fName := 'Поле'; {Эксперимент пытаюсь задать значение полю. 
 По идее если файла нет, то нет никакого объекта. 
(Точнее сработало исключение и тут же вызван  деструктор). 
А значит данная инструкция должна давать ошибку.  
Но она никакой ошибки не дает. 
При том что исключение в конструкторе срабатывает (Вижу сообщение самого исключения: 'Файла нет!' и сообщение "Сейчас вызову деструктор!")}




Такое впечатление, что  мой деструктор очищает не всю память...




Это сообщение отредактировал(а) PsiMagistr - 2.6.2010, 15:11


--------------------
"Арфы нет? Возьмите бубен!

Ребята, будем жить!"

 (с) "В бой идут одни старики"

---

"ИЕ" - один из самых сумасшедших браузеров в нашей галактике.
PM MAIL   Вверх
CodeMonkey
Дата 2.6.2010, 16:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1839
Регистрация: 24.6.2008
Где: Россия, Тверь

Репутация: 29
Всего: 89



Сыграем в игру (люблю я это дело) smile

Буратине дали три яблока. Сколько яблок у буратины? Думаете три? Ничего подобного. Никто же не сказал, сколько яблок было до того, как ему дали три.

Мораль истории: инициализируйте переменные.

Способны ли вы теперь с этой подсказкой найти объяснение видимому поведению? ;)


--------------------
Опытный программист на C++ легко решает любые не существующие в Паскале проблемы.
PM MAIL WWW ICQ Skype GTalk Jabber   Вверх
PsiMagistr
Дата 2.6.2010, 18:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 479
Регистрация: 31.12.2009

Репутация: 1
Всего: 1



Благодарю, CodeMonkey. ))) Развивайте мысль. )))) О каких переменных идет речь в данном случае? Насколько я понимаю, все переменные какими мы обладаем вроде получили инициализацию, во всяком случае так считает компилятор.

Внешний указатель вроде только один. MyObject.

переменная-поле внутри класса fName.

А теперь Ваши соображения? )









--------------------
"Арфы нет? Возьмите бубен!

Ребята, будем жить!"

 (с) "В бой идут одни старики"

---

"ИЕ" - один из самых сумасшедших браузеров в нашей галактике.
PM MAIL   Вверх
CodeMonkey
Дата 2.6.2010, 18:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1839
Регистрация: 24.6.2008
Где: Россия, Тверь

Репутация: 29
Всего: 89



Строка

Код
MyObJect:=TMyClass.Create('Файл.txt');


Раскладывается на более простые действия так: 

- вызвать конструктор
- ссылку, которую вернул конструктор, записать в переменную MyObject.

Соответственно, если конструктор возбуждает исключение, то выполнение прерывается и запись чего-либо в MyObject не происходит. Откуда следует, что в MyObject остаётся то, что было в ней до вышеуказанной строчки - т.е. мусор.

Очевидно, что вызов

Код
MyObject.fName := 'Поле';


Когда в MyObject лежит мусор, приводит к произвольному поведению. Это может быть нормальная работа, это может быть access violation - что угодно.

P.S. Проверка

Код
If Assigned(self) then


В деструкторе излишня - этим занимается Free. Уберите.


--------------------
Опытный программист на C++ легко решает любые не существующие в Паскале проблемы.
PM MAIL WWW ICQ Skype GTalk Jabber   Вверх
PsiMagistr
Дата 3.6.2010, 13:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 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


--------------------
"Арфы нет? Возьмите бубен!

Ребята, будем жить!"

 (с) "В бой идут одни старики"

---

"ИЕ" - один из самых сумасшедших браузеров в нашей галактике.
PM MAIL   Вверх
Демо
Дата 3.6.2010, 15:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1278
Регистрация: 3.11.2005

Репутация: 7
Всего: 50



Цитата(PsiMagistr @  3.6.2010,  13:12 Найти цитируемый пост)
Вы пишите If Assigned(self) then в деструкторе лишняя? Вот тут я не могу понять, почему? Да во Free есть эта встроенная проверка. Но именно Free нигде не вызывается.  До него дело не доходит, просто. Вызывается голый деструктор.А попытка вызвать Free в деструкторе:self.free; вместо inherited Destroy;


Деструктор вызывается только для созданного объекта. т.е. Self существует по-определению.

Далее - предка, для которого нужно было бы вызвать свой деструктор, нет.

Код

type TMyClass = class //Начало описания класса


Код

Destructor TMyClass.Destroy; Реализация деструктора.
Begin
  If Assigned(self) then //Если указатель не равен nil связан с объектом то:
  begin
    ShowMessage('Сейчас вызову деструктор!'); //Даю сообщение и
    Inherited Destroy; //Вызов деструктора предка, освобождение памяти.
  end;
end;


Вместо всего этого достаточно

destructor TMyClass.Destroy;
begin
    ShowMessage('Сейчас вызову деструктор!'); //Даю сообщение и
end;



--------------------
    
PM MAIL ICQ Skype   Вверх
PsiMagistr
Дата 3.6.2010, 15:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 479
Регистрация: 31.12.2009

Репутация: 1
Всего: 1



Демо, благодарю. 


Цитата(Демо @  3.6.2010,  15:16 Найти цитируемый пост)
Далее - предка, для которого нужно было бы вызвать свой деструктор, нет.


Забавно. Я полагал, что предок всегда есть (TObject хотя бы).

Правильно ли я вас понял, что невозможно вызвать деструктор для несуществующего объекта?



Мне бы как-то попытаться сделать так, чтобы:



Код

MyObject:= MyClass.Create('test.txt'); // Пытаюсь создать объект.


При отсутствии файла мне мало просто вызвать деструктор. Мне важно, чтобы в MyObject был nil. Но вот как его туда заслать?  Ведь при исключении тут же вызывается деструктор, который разрушает все и в конечном итоге - мусор в MyObject.

Или я не так понимаю?
 


 


Это сообщение отредактировал(а) PsiMagistr - 3.6.2010, 16:50


--------------------
"Арфы нет? Возьмите бубен!

Ребята, будем жить!"

 (с) "В бой идут одни старики"

---

"ИЕ" - один из самых сумасшедших браузеров в нашей галактике.
PM MAIL   Вверх
Mikel
Дата 3.6.2010, 15:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник Клуба
Сообщений: 882
Регистрация: 30.3.2002
Где: Саратов

Репутация: нет
Всего: 2



А почему бы не сделать что-н типа:

Код

MyObj:=TMyObj.Create;
if not MyObj.Init 
then FreeAndNil(MyObj)
else ...


Вынести просто ту логику в инит...


--------------------
...so remember, it's better to burn out than to fade away
PM MAIL ICQ   Вверх
PsiMagistr
Дата 3.6.2010, 16:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 479
Регистрация: 31.12.2009

Репутация: 1
Всего: 1



Mikel, О, это интересная идея.

А что есть init? Как  я понял свойство проверки инициализации?

P.S. Я очень мало знаком с внутренней структурой объектов. К ООП приступил недавно.


--------------------
"Арфы нет? Возьмите бубен!

Ребята, будем жить!"

 (с) "В бой идут одни старики"

---

"ИЕ" - один из самых сумасшедших браузеров в нашей галактике.
PM MAIL   Вверх
Mikel
Дата 3.6.2010, 16:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник Клуба
Сообщений: 882
Регистрация: 30.3.2002
Где: Саратов

Репутация: нет
Всего: 2



Initом я просто обозвал функцию в которую предлагаю тебе вынести всю логику из Create. В Create только создавать объект.


--------------------
...so remember, it's better to burn out than to fade away
PM MAIL ICQ   Вверх
PsiMagistr
Дата 3.6.2010, 16:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 479
Регистрация: 31.12.2009

Репутация: 1
Всего: 1



Mikel,  благодарю от души за участие. Понимаете суть моей задачи в чем... Я загорелся идеей фикс зашить в класс всю работу с файлами.

Т.е. Есть файл (или соотвествующая запись в нем) - конструктор загружает данные в поля и создает объект. Нет файла - нет объекта. А в объектном указателе в этом случае - Nil. Причем все это должно крутиться внутри класса. В этом весь смак. Обслужить все внешними проверками можно, но тогда нет особого смысла и в классе. Я хочу выжать максимум универсальности.


--------------------
"Арфы нет? Возьмите бубен!

Ребята, будем жить!"

 (с) "В бой идут одни старики"

---

"ИЕ" - один из самых сумасшедших браузеров в нашей галактике.
PM MAIL   Вверх
Демо
Дата 3.6.2010, 17:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1278
Регистрация: 3.11.2005

Репутация: 7
Всего: 50



Цитата(PsiMagistr @  3.6.2010,  15:39 Найти цитируемый пост)
Забавно. Я полагал, что предок всегда есть (TObject хотя бы).


Нет предка, для которого необходимо вызвать дополнительно деструктор.
Хотя я всегда использую inherited Destroy  в своём коде. Это позволяет никогда не забывать вызывать деструктор предка. 


Цитата(PsiMagistr @  3.6.2010,  15:39 Найти цитируемый пост)
При отсутствии файла мне мало просто вызвать деструктор. Мне важно, чтобы в MyObject был nil. Но вот как его туда заслать?  Ведь при исключении тут же вызывается деструктор, который разрушает все и в конечном итоге - мусор в MyObject.Или я не так понимаю?


CodeMonkey уже писал тебе о том, что перед созданием объекта переменную нужно проинициализировать.

т.е. 

Код

MyObject := nil;
MyObject := TMyObject.Create;

В случае возникновения исключения значение MyObject не изменится.
Не путай псевдопеременную Self с обычной переменной-ссылкой на объект.


Это сообщение отредактировал(а) Демо - 3.6.2010, 17:16


--------------------
    
PM MAIL ICQ Skype   Вверх
PsiMagistr
Дата 3.6.2010, 17:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 479
Регистрация: 31.12.2009

Репутация: 1
Всего: 1



Демо, дружище. Именно так я и пытался писать. Более того я писал проверки, чтобы отследить:

Код

procedure TForm1.Button1Click(Sender: TObject);

begin

MyObject:= nil;

MyObJect:=TMyClass.Create('Проба.txt'); 

If MyObject = nil then

ShowMessage('Указатель нулевой!'); //Жду сообщения как пришествия, а оно не спешит...


end;



Это сообщение отредактировал(а) PsiMagistr - 3.6.2010, 17:23


--------------------
"Арфы нет? Возьмите бубен!

Ребята, будем жить!"

 (с) "В бой идут одни старики"

---

"ИЕ" - один из самых сумасшедших браузеров в нашей галактике.
PM MAIL   Вверх
Демо
Дата 3.6.2010, 17:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1278
Регистрация: 3.11.2005

Репутация: 7
Всего: 50



А каким образом ты можешь дождаться сообщения, если на строке MyObJect:=TMyClass.Create('Проба.txt');  у тебя возникает исключение, и следующие строки не выполняются?


--------------------
    
PM MAIL ICQ Skype   Вверх
PsiMagistr
Дата 3.6.2010, 17:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 479
Регистрация: 31.12.2009

Репутация: 1
Всего: 1



А вот тут я совсем не понял чего-то. Допустим возникает исключение. И что? Оно же в конструкторе возникает. Ну конструктор, ясное дело, обваливается.  Но проверка на nill  не в конструкторе, она внешняя, из программы, в обработчике кнопки. По идее должен был быть переход к след шагу, неужели же обваливается вся процедура, где этот злосчастный конструктор вызван? Но тогда получается что из за исключения в конструкторе вся программа клеит ласты)))







Это сообщение отредактировал(а) PsiMagistr - 3.6.2010, 17:46


--------------------
"Арфы нет? Возьмите бубен!

Ребята, будем жить!"

 (с) "В бой идут одни старики"

---

"ИЕ" - один из самых сумасшедших браузеров в нашей галактике.
PM MAIL   Вверх
bems
Дата 3.6.2010, 17:59 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 3400
Регистрация: 5.1.2006

Репутация: 18
Всего: 88



Цитата(Демо @  1.6.2010,  20:59 Найти цитируемый пост)
При возникновении в конструкторе исключения будет немедленно вызван деструктор, а объект не будет создан.
Во этом случае код в деструкторе нужно писать, учитывая, что в конструкторе может возникнуть исключение. 
Деструктор нужно писать так всегда. Без исключений.

Цитата(Демо @  2.6.2010,  09:06 Найти цитируемый пост)
class function/procedure - специальный вид функций, которые могут выполняться без создания экземпляра класса, не имеют доступа к ссылке на экземпляр класса (Self).
Self есть, но он указывает на класс, а не наэкземпляр (нету селфа только у статических классовых методов)

Цитата(PsiMagistr @  3.6.2010,  17:36 Найти цитируемый пост)
А вот тут я совсем не понял чего-то. Допустим возникает исключение. И что? Оно же в конструкторе возникает. Ну конструктор, ясное дело, обваливается.  Но проверка на nill  не в конструкторе, она внешняя, из программы, в обработчике кнопки. По идее должен был быть переход к след шагу, а то получается что из за исключения в конструкторе вся программа клеит ласты)))
После выполнения деструктора исключение остаётся необработанным, и поднимается вверх по стеку вызовов (с выполнением всех секций finally), до ближайшего по стеку обработчика (это может быть except или обработчик исключений из TApplication, который просто выводит сообщение)


Это сообщение отредактировал(а) bems - 3.6.2010, 18:01


--------------------
Обижено школьников: 8
PM MAIL   Вверх
PsiMagistr
Дата 3.6.2010, 18:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 479
Регистрация: 31.12.2009

Репутация: 1
Всего: 1



bems, и что вы предлагаете? Вот у меня исключение в конструкторе вызывается и весь обработчик кнопки, где я этот конструктор призвал обваливается. 

Это сообщение отредактировал(а) PsiMagistr - 3.6.2010, 18:31


--------------------
"Арфы нет? Возьмите бубен!

Ребята, будем жить!"

 (с) "В бой идут одни старики"

---

"ИЕ" - один из самых сумасшедших браузеров в нашей галактике.
PM MAIL   Вверх
bems
Дата 3.6.2010, 18:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 3400
Регистрация: 5.1.2006

Репутация: 18
Всего: 88



PsiMagistr, да, обваливается. Ты видишь в этом что-то плохое?
Если ты знаешь что делать в случае отсутствия файла, то пиши секцию except

Это сообщение отредактировал(а) bems - 3.6.2010, 18:32


--------------------
Обижено школьников: 8
PM MAIL   Вверх
Демо
Дата 3.6.2010, 19:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1278
Регистрация: 3.11.2005

Репутация: 7
Всего: 50



Цитата(bems @  3.6.2010,  17:59 Найти цитируемый пост)
Деструктор нужно писать так всегда. Без исключений.


Это ещё почему?

Код


{TObject}

destructor TObject.Destroy;
begin
end;

procedure TObject.Free;
begin
  if Self <> nil then
    Destroy;
end;



Цитата(PsiMagistr @  3.6.2010,  18:26 Найти цитируемый пост)
bems, и что вы предлагаете? Вот у меня исключение в конструкторе вызывается и весь обработчик кнопки, где я этот конструктор призвал обваливается. 


Ты не умеешь обрабатывать исключения?

Код

procedure TForm1.Button1Click(Sender: TObject);
begin
  try
    MyObJect:=TMyClass.Create('Проба.txt'); 
  except
    ShowMessage('Ошибка!'); //Жду сообщения как пришествия, а оно не спешит...
  end;
end;



--------------------
    
PM MAIL ICQ Skype   Вверх
PsiMagistr
Дата 3.6.2010, 19:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 479
Регистрация: 31.12.2009

Репутация: 1
Всего: 1



Демо, нет. НЕ умею. Честно. Я только к дельфи приступил. С книгой сижу.

 Вот реализация конструктора:

Код

constructor TMyClass.Create(FileName:String);
begin

inherited Create; //Вызов конструктора предка
if FileExists(ExtractFilePath(Application.ExeName)+FileName) = true then //Если файл существует:

begin
Fname := 'Задаем по умолчанию';  //Присвоение полю FName
ShowMessage('Файл есть'); //
end

Else raise Exception.Create('Нет файла!') //Иначе поднимаем исключение. 

end;


Вот только как его обработать, чтоб после выполнения исключения обработчик, где будет вызываться конструктор не обваливался?

В случае отсутствия файла - присвоить указателю на объект nil. Но поскольку я его и так инициализировал с nil а меняться он не должен. то в случае отсутствия можно ничего не делать. Поскольку деструктор возникнет автоматом.

Это сообщение отредактировал(а) PsiMagistr - 3.6.2010, 19:16


--------------------
"Арфы нет? Возьмите бубен!

Ребята, будем жить!"

 (с) "В бой идут одни старики"

---

"ИЕ" - один из самых сумасшедших браузеров в нашей галактике.
PM MAIL   Вверх
Демо
Дата 3.6.2010, 19:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1278
Регистрация: 3.11.2005

Репутация: 7
Всего: 50




Код

  TMyObject=class
  private
    FName: String;
    FS: TFileStream;
  public
    constructor CreateObj(const FilePath: String);
    destructor Destroy; override;
    class function Create(const FilePath: String): TMyObject;
  end;



Код

{ TMyObject }

class function TMyObject.Create(const FilePath: String): TMyObject;
begin
  Result := nil;
  if not FileExists(FilePath) then Exit;
  try
    Result := TMyObject.CreateObj(FilePath);
  except
// Нам всё равно, что за исключение. Гасим его
  end;
end;

constructor TMyObject.CreateObj(const FilePath: String);
begin
  FName := FilePath;
  FS := TFileStream.Create(FName,fmOpenRead);
end;

destructor TMyObject.Destroy;
begin
  FS.Free;
  inherited;
end;




--------------------
    
PM MAIL ICQ Skype   Вверх
CodeMonkey
Дата 3.6.2010, 20:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1839
Регистрация: 24.6.2008
Где: Россия, Тверь

Репутация: 29
Всего: 89



Цитата(PsiMagistr @  3.6.2010,  14:12 Найти цитируемый пост)
Неплохо было бы в деструкторе класса прописать чтобы указатель получал хотя бы Nil

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

Но если сильно охота, то можно - в качестве примера посмотрите реализацию Application.CreateForm (вызов смотреть в DPR-файле, а реализацию - в Forms.pas). Но делать так без веских причин я бы не стал.

Цитата(PsiMagistr @  3.6.2010,  14:12 Найти цитируемый пост)
Вы пишите If Assigned(self) then в деструкторе лишняя? Вот тут я не могу понять, почему?

Потому что Self = nil в деструкторе - это глюк (почему? уже сказал Demo: при вызове из конструктора Self гарантировано не-nil, а при внешнем вызове вы вызываете Free; хотя формально вы вполне можете вызывать TForm(nil).Destroy). Такого не должно быть. А раз не должно быть, то вылететь с access violation - вполне нормальный вариант. Можете не засорять исходники лишними проверками.

Цитата(Демо @  3.6.2010,  16:16 Найти цитируемый пост)
Вместо всего этого достаточно

Только надо понимать, что "достаточно" <> "нужно так делать".

Цитата(PsiMagistr @  3.6.2010,  16:39 Найти цитируемый пост)
Я полагал, что предок всегда есть (TObject хотя бы).

Верно.

Цитата(PsiMagistr @  3.6.2010,  16:39 Найти цитируемый пост)
Правильно ли я вас понял, что невозможно вызвать деструктор для несуществующего объекта?

Сделать можно что угодно:

Код
TForm(nil).Destroy;


Но тогда вы сами себе буратино.

Цитата(PsiMagistr @  3.6.2010,  16:39 Найти цитируемый пост)
Мне важно, чтобы в MyObject был nil. Но вот как его туда заслать?  Ведь при исключении тут же вызывается деструктор, который разрушает все и в конечном итоге - мусор в MyObject.


Код
MyObject := nil;
MyObject := TMyObject.Create('filename');

// или:

try
  MyObject := TMyObject.Create('filename');
except
  MyObject := nil;
  raise;
end;


Цитата(PsiMagistr @  3.6.2010,  18:36 Найти цитируемый пост)
Но проверка на nill  не в конструкторе, она внешняя, из программы, в обработчике кнопки. По идее должен был быть переход к след шагу, неужели же обваливается вся процедура, где этот злосчастный конструктор вызван? Но тогда получается что из за исключения в конструкторе вся программа клеит ласты)))

Рекомендую почитать.

Добавлено через 5 минут и 22 секунды
Согласен с bems-ом по поводу деструктора.

Цитата(Демо @  3.6.2010,  20:09 Найти цитируемый пост)
Это ещё почему?

По той простой причине, что пустой конструктор - это деталь реализации, а не стандарт ООП языка. Вот выйдет Fulcrum - откуда вы знаете, может там в деструкторе что-то будет, чтобы сгладить косяки платформы? Вы уверены, что в FreePascal (подставьте сюда любой компилятор Паскаля, с которым вы не знакомы) деструктор тоже пустой?

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


--------------------
Опытный программист на C++ легко решает любые не существующие в Паскале проблемы.
PM MAIL WWW ICQ Skype GTalk Jabber   Вверх
Демо
Дата 3.6.2010, 22:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1278
Регистрация: 3.11.2005

Репутация: 7
Всего: 50



Цитата(CodeMonkey @  3.6.2010,  20:32 Найти цитируемый пост)
По той простой причине, что пустой конструктор - это деталь реализации, а не стандарт ООП языка. Вот выйдет Fulcrum - откуда вы знаете, может там в деструкторе что-то будет, чтобы сгладить косяки платформы? Вы уверены, что в FreePascal (подставьте сюда любой компилятор Паскаля, с которым вы не знакомы) деструктор тоже пустой?Но это не главное. А главное в том, что класс может быть изменён в процессе рефакторинга позже. В том числе, он может сменить предка. Вызов унаследованных конструкторов и деструкторов всегда - это простое правило, которое поможет вам избежать потенциальных проблем.


Да согласен я-)

Смысл фразы в том, что нужно всегда знать, что делаешь.
Если я знаю в данный момент, что в TObject мне ничего не нужно освобождать, то с полным сознанием и уверенностью могу не вызывать родительский деструктор, учитывая, что другоим колмпилятором я не буду пользоваться...




--------------------
    
PM MAIL ICQ Skype   Вверх
bems
Дата 4.6.2010, 00:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 3400
Регистрация: 5.1.2006

Репутация: 18
Всего: 88



Цитата(Демо @  3.6.2010,  19:09 Найти цитируемый пост)
Это ещё почему?
Потому что очень трудно следить за каждым конструктором на предмет озможности исключений. Правильнее считать что исключение может возникнуть в любом месте любого конструктора (собственно это не далеко от истины). Если моих слов не достаточно то вот:
Цитата(http://docwiki.embarcadero.com/RADStudio/en/Methods)
When an exception is raised during the creation of an object, Destroy is automatically called to dispose of the unfinished object. This means that Destroy must be prepared to dispose of partially constructed objects. Because a constructor sets the fields of a new object to zero or empty values before performing other actions, class-type and pointer-type fields in a partially constructed object are always nil. A destructor should therefore check for nil  values before operating on class-type or pointer-type fields. Calling the Free method (defined in TObject) rather than Destroy offers a convenient way to check for nil  values before destroying an object. 

А твой пример ни к селу ни к городу. Ясно, что если деструктор ничего не делает, то и проверять нечего (даже если бы в конструкторе TObject и могло возникнуть исключение)

Добавлено через 12 минут и 42 секунды
Цитата(CodeMonkey @  3.6.2010,  20:32 Найти цитируемый пост)
Согласен с bems-ом по поводу деструктора.
...
Вызов унаследованных конструкторов и деструкторов всегда - это простое правило, которое поможет вам избежать потенциальных проблем.

что-то меня не поняли. Я говорил не о вызове унаследованного деструктора, а о том, чтобы всегда писать деструктор так, чтобы он мог разрушать недосозданный объект


--------------------
Обижено школьников: 8
PM MAIL   Вверх
Демо
Дата 4.6.2010, 01:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1278
Регистрация: 3.11.2005

Репутация: 7
Всего: 50



Цитата(bems @  4.6.2010,  00:33 Найти цитируемый пост)
что-то меня не поняли. Я говорил не о вызове унаследованного деструктора, а о том, чтобы всегда писать деструктор так, чтобы он мог разрушать недосозданный объект


Действительно не поняли.
Я-то говорил именно об обязательности вызова родительского деструктора.


--------------------
    
PM MAIL ICQ Skype   Вверх
bems
Дата 4.6.2010, 01:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 3400
Регистрация: 5.1.2006

Репутация: 18
Всего: 88



Цитата(Демо @  3.6.2010,  19:52 Найти цитируемый пост)
// Нам всё равно, что за исключение. Гасим его

Даже если это нехватка памяти или Assert?


--------------------
Обижено школьников: 8
PM MAIL   Вверх
Демо
Дата 4.6.2010, 09:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1278
Регистрация: 3.11.2005

Репутация: 7
Всего: 50



Цитата(bems @  4.6.2010,  01:28 Найти цитируемый пост)
Даже если это нехватка памяти или Assert?


Ну если нехватка памяти, то вряд ли можно что-то ещё сделать.
А работу с Assert надо заранее проектировать-)


--------------------
    
PM MAIL ICQ Skype   Вверх
PsiMagistr
Дата 4.6.2010, 12:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 479
Регистрация: 31.12.2009

Репутация: 1
Всего: 1



Ребята, благодарю всех. Огромное СПС! Сейчас читаю информацию предоставленную, CodeMonkey :

Итак как я сделал:

Реализация конструктора:

Код

constructor TMyClass.Create(FileName:String);
begin
inherited Create; //Вызов конструктора предка.
if FileExists(ExtractFilePath(Application.ExeName)+FileName) = true then //Если файл есть то:

begin
Fname := 'Умолчание';  //Присваиваем значение по умолчанию полю FName
ShowMessage('Есть!'); //
end

Else raise Exception.Create('Нет файла!');
end;



Реализация деструктора:

Код

Destructor TMyClass.Destroy;
Begin
ShowMessage('Вызываю деструктор!');
Inherited Destroy;
end;




А в коде кнопки:

Код

procedure TForm1.Button1Click(Sender: TObject);

begin
MyObject:= nil;

try
MyObJect:=TMyClass.Create('Проба.txt'); //Пытаюсь создать конструктор

Except //И словить исключение:

if MyObject = nil then ShowMessage('Указатель Нулевоой');
end;
end;


Запускать это из самой среды бесполезно - Дельфи споткнется в конструкторе. Поэтому компилирую файл. Все как будто получается. И деструктор вызывается. Но таблички:

Код

Else raise Exception.Create('Нет файла!'); //Не возникает.





 

Это сообщение отредактировал(а) PsiMagistr - 4.6.2010, 12:41


--------------------
"Арфы нет? Возьмите бубен!

Ребята, будем жить!"

 (с) "В бой идут одни старики"

---

"ИЕ" - один из самых сумасшедших браузеров в нашей галактике.
PM MAIL   Вверх
CodeMonkey
Дата 4.6.2010, 12:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1839
Регистрация: 24.6.2008
Где: Россия, Тверь

Репутация: 29
Всего: 89



Код
if FileExists(ExtractFilePath(Application.ExeName)+FileName) = true then


= True - излишне. Это всё равно, что спрашивать "если да равно да то" или "включен ли компьютер" (если бы компьютер был бы выключен, программа не смогла бы задать этот вопрос).

Надо:
Код
if FileExists(ExtractFilePath(Application.ExeName)+FileName) then


Цитата(PsiMagistr @  4.6.2010,  13:12 Найти цитируемый пост)
Дельфи споткнется в конструкторе

Это уведомление отладчика сделано исключительно для вашего удобства, чтобы вы могли исследовать ситуацию, приводящую к ошибке, прямо на месте. Если вы не хотите этого делать - просто жмите Continue (в новых Delphi) или Run/Run (в старых).

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

Цитата(PsiMagistr @  4.6.2010,  13:12 Найти цитируемый пост)
Но таблички Не возникает

Вы же сами её заблокировали блоком except.

Далее, проверять в except MyObject на nil - излишне, т.к. если вы попали в блок except, то только потому, что создание объекта обвалилось. Это всё равно, что проверять Self <> nil в деструкторе. Поэтому:

Код
try
  MyObJect:=TMyClass.Create('Проба.txt'); //Пытаюсь создать конструктор
Except //И словить исключение:
  MyObJect:=nil;
  ShowMessage('Указатель Нулевоой');
end;
end;


А вот и табличка:

Код
try
  MyObJect:=TMyClass.Create('Проба.txt'); //Пытаюсь создать конструктор
Except //И словить исключение:
  MyObJect:=nil;
  ShowMessage('Указатель Нулевоой');
  raise;
end;
end;


Или:

Код
try
  MyObJect:=TMyClass.Create('Проба.txt'); //Пытаюсь создать конструктор
Except //И словить исключение:
  MyObJect:=nil;
  ShowMessage('Указатель Нулевоой');
  Application.HandleException(nil);
end;
end;


В общем, миллион способов. А выбор зависит от того, зачем это надо, и что вы будете делать дальше. И я бы, на вашем месте, рассказал бы побольше про это.


--------------------
Опытный программист на C++ легко решает любые не существующие в Паскале проблемы.
PM MAIL WWW ICQ Skype GTalk Jabber   Вверх
PsiMagistr
Дата 4.6.2010, 12:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 479
Регистрация: 31.12.2009

Репутация: 1
Всего: 1



Я попробую в двух словах. Решил писать ролевую игру. Когда то давно писал на VB первый экземпляр. Получилось. Правда реализовывать ООП я не стал, обошелся процедурным программированием.

Основная текущая задача - зашить в класс работу с файлами. 

Вот например файл персонажа. Изначально там служебная информация, недоступная игроку. (параметры умолчания).

Например:

Жизнь-100
Интеллект-50
Ловкость=30

И .т.д. 

Что это значит. Когда мы создаем нового персонажа, конструктор объекта "Персонаж" читает служебную запись файла, считывает переменные умолчания и на основании этого строит вторую запись - это уже реальный персонаж, доступ к которому имеет игрок. 

В классе я пытаюсь охватить все возможные нюансы работы с файлами. Например обращение из основной программы:

MyObject.Lovkost:=30; 

к свойству "Ловкость", будет означать не только присвоение, но и запись соответствующей информации в файл.









Это сообщение отредактировал(а) PsiMagistr - 4.6.2010, 13:04


--------------------
"Арфы нет? Возьмите бубен!

Ребята, будем жить!"

 (с) "В бой идут одни старики"

---

"ИЕ" - один из самых сумасшедших браузеров в нашей галактике.
PM MAIL   Вверх
CodeMonkey
Дата 4.6.2010, 13:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1839
Регистрация: 24.6.2008
Где: Россия, Тверь

Репутация: 29
Всего: 89



Так, а теперь, внимание, вопрос (С)

Положим вы создаёте персонажа из файла TMyObject.Create('SavedGame01.dat');

Положим файл не найден, заблокирован антивирусом или тупо повреждён - вы выбрасываете исключение, отлично.

Но. Дальше-то вы что делаете? А дальше вы обрабатываете эту ошибку, показывая мессагу, производя откат или что там ещё придумаете. Но при этом вы не обращаетесь к MyObject. Почему? Потому что он был не создан. Зачем вам обращаться к несуществующему объекту? Я имею ввиду, что вы просто не доходите до этого кода, например:

Код
// какой-то код
MyObject := TMyObject.Create('SavedGame01.dat');
// ещё какой-то код
MyObject.ShowOnScreen; // <- гарантировано <> nil, поэтому "if Assigned(MyObject) then" излишне 


Если создание объекта проваливается, то до использования объекта ниже вы не доходите. Именно поэтому я сказал, что ваши попытки сделать MyObJect := nil выглядят очень подозрительно. 

Как, в целом, узнают, что MyObJect <> nil? По месту выполнения кода.


--------------------
Опытный программист на C++ легко решает любые не существующие в Паскале проблемы.
PM MAIL WWW ICQ Skype GTalk Jabber   Вверх
PsiMagistr
Дата 4.6.2010, 14:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 479
Регистрация: 31.12.2009

Репутация: 1
Всего: 1



CodeMonkey, благодарен безмерно. попробую Вам объяснить в чем штука со всеми нюансами.


Итак, у нас есть файл записей (record). Первая запись данного файла - это служебная информация прототипа. Доступ игрока к ней закрыт.

Остальные записи в файле это параметры реальных персонажей.

В классе будут ДВА конструктора CreateOpen и CreateNew.

Если игрок будет открывать уже созданного персонажа то вызываем конструктор CreateOpen, куда передадим лог-пасс.  CreateOpen будет проверять существование файла. Если нет, генерируем сообщение "Не хватает служебных ресурсов". Обваливаем конструктор исключением и  закрывем программу. Если файл есть, обходим его ночным дозором , поочередно забираем в переменные-поля параметры каждой записи и сравниваем их лог-пассы с лог-пассом введенным пользователем. Если совпадает то:

Грузим конструктором туда все данные из найденной записи. И создаем, наконец, объект. А если не совпадает: 

Генерируем сообщение "Неверный лог-пасс", обрушиваем конструктор и не создаем объект. Введет пользователь новый лог-пасс, нажмет на кнопочку и... Будет новая попытка создания объекта.

Второй конструктор CreatNew занимается другим. Он

Проверяет, существует ли файл. Если да, то берет служебную первую запись. Грузит значения в переменные. Берет лог-пасс введенный пользователем снова грузит в переменные (подменяя там формальные значения-умолчания взятые из служебной записи). и наконец создает вторую запись. 

Вторая запись - действительный персонаж. К нему впоследствии  обращается игрок.

 



Это сообщение отредактировал(а) PsiMagistr - 4.6.2010, 15:01


--------------------
"Арфы нет? Возьмите бубен!

Ребята, будем жить!"

 (с) "В бой идут одни старики"

---

"ИЕ" - один из самых сумасшедших браузеров в нашей галактике.
PM MAIL   Вверх
CodeMonkey
Дата 4.6.2010, 14:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1839
Регистрация: 24.6.2008
Где: Россия, Тверь

Репутация: 29
Всего: 89



Ээээ.... ну? Что-то я не понял, что вы хотели сказать. 

Зачем тогда вам в этом сценарии обнуление переменной MyObject при неудаче? Если в обоих случаях при исключении вы просто игнорируете переменную и не обращаетесь к ней?

P.S. Конструктор не обязательно должен начинаться с Create. Удобно создать два конструктора так:
Код
type
  TMyObject = class
  ...
    constructor Create(...);
    constructor Open(...);
  end;

Ибо вызовы TMyObject.Create(...) и TMyObject.Open(...) смотрятся как-то "читабельнее", нежели TMyObject.CreateNew(...) и TMyObject.CreateOpen(...).

Это сообщение отредактировал(а) CodeMonkey - 4.6.2010, 14:48


--------------------
Опытный программист на C++ легко решает любые не существующие в Паскале проблемы.
PM MAIL WWW ICQ Skype GTalk Jabber   Вверх
PsiMagistr
Дата 4.6.2010, 14:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 479
Регистрация: 31.12.2009

Репутация: 1
Всего: 1



CodeMonkey, свершенно верно. В реальности в случае обрушения в конструкторе в указателе может остаться даже "мусор умолчания" (хотя по моему по умолчанию указатель равен - nil). Объекта то все равно нет и делать нам нечего.

 Но мусор для меня нежелателен, хочу чтоб все под контролем было .



Это сообщение отредактировал(а) PsiMagistr - 4.6.2010, 14:58


--------------------
"Арфы нет? Возьмите бубен!

Ребята, будем жить!"

 (с) "В бой идут одни старики"

---

"ИЕ" - один из самых сумасшедших браузеров в нашей галактике.
PM MAIL   Вверх
PsiMagistr
Дата 4.6.2010, 16:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 479
Регистрация: 31.12.2009

Репутация: 1
Всего: 1



Вот еще какая тонкая штука, нюансик.

Код

//При закрытии глав. формы написал:

MyObject.Free;

//Ну это типа мы  создавали объекты, они успешно появлялись, а теперь закрываем прогу, гасим свет.



//Дескать баста, финита уходим, освободите память))).

//Но плюс к этому записал исключение в конструкторе (насчет того, что файл не найдется) а в кнопке его обработал:

procedure TForm1.Button1Click(Sender: TObject); //Кнопка

begin

MyObject:= nil;

try //Пытаюсь вызвать объект.

MyObJect:=TMyClass.Create('Проба.txt'); //Файла нет, создание объекта провалено. Вызывается деструктор!

Except

ShowMessage('Файл не найден!'); //Мол нет ресурсов, делать нечего. 

Form1.Close; //Уходим Обратите внимание на этот оператор.

end;
end;

{Допустим файл есть.  Если файл есть - объект есть. Работаем, при закрытии формы спокойно освобождаемся через MyObject.Free, А вдруг файла нет? Трах-бах - исключение в конструкторе. Деструктор пошел, ясное дело. Потом вызывается оператор Close. Но в обработчике Close записано //MyObject.Free. А объекта то в данном случае нет, деструктор уже вызвался.  

Не навредит ли этот MyObject.Free в данном случае У меня ошибок не выходит, но шут его знает как на самом деле

Кстати именно поэтому я хотел сделать вернуть в указатель - Nil при неудаче создания объекта. Тогда можно было бы написать при закрытии формы:}

If Object<>nil then MyObject.Free;


ДАННЫЙ ВОПРОС СНИМАЕТСЯ. Я голова садовая, совсем забыл, что Free контролирует указатель и только в случае указатель <> Nil вызывает деструктор.




Это сообщение отредактировал(а) bems - 4.6.2010, 17:49


--------------------
"Арфы нет? Возьмите бубен!

Ребята, будем жить!"

 (с) "В бой идут одни старики"

---

"ИЕ" - один из самых сумасшедших браузеров в нашей галактике.
PM MAIL   Вверх
CodeMonkey
Дата 4.6.2010, 18:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1839
Регистрация: 24.6.2008
Где: Россия, Тверь

Репутация: 29
Всего: 89



Цитата(PsiMagistr @  4.6.2010,  15:58 Найти цитируемый пост)
Но мусор для меня нежелателен, хочу чтоб все под контролем было .


Так, давайте ещё раз.

Есть два сценария использования любого объекта.

Первый - локально:

Код
var
  MyObject: TMyObject;
begin
  // какой-то код
  MyObject := TMyObject.Create(...);
  try
    // работа с MyObject
  finally
    FreeAndNil(MyObject);
  end;
  // ещё какой-то код
end;


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

Сценарий 2: глобально

Здесь MyObject - глобальная переменная или поле объекта (например, формы)

Код
procedure TSomeClass.SomeInitMethod;
begin
  // какой-то код
  MyObject := TMyObject.Create(...);
  // какой-то код
end;

...

procedure TSomeClass.SomeFinalizeMethod;
begin
  // какой-то код
  FreeAndNil(MyObject);
  // какой-то код
end;


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

P.S. Вместо 

Код
If Object<>nil then MyObject.Free;


Лучше делать 

Код
FreeAndNil(MyObject);



--------------------
Опытный программист на C++ легко решает любые не существующие в Паскале проблемы.
PM MAIL WWW ICQ Skype GTalk Jabber   Вверх
PsiMagistr
Дата 6.6.2010, 12:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 479
Регистрация: 31.12.2009

Репутация: 1
Всего: 1



Благодарю сердечно, CodeMonkey.
 


--------------------
"Арфы нет? Возьмите бубен!

Ребята, будем жить!"

 (с) "В бой идут одни старики"

---

"ИЕ" - один из самых сумасшедших браузеров в нашей галактике.
PM MAIL   Вверх
PsiMagistr
Дата 8.6.2010, 12:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 479
Регистрация: 31.12.2009

Репутация: 1
Всего: 1



Скоро буду готов к описанию классов. Возник следующий нюанс:

Все переменные класса (поля), должны сохраняться в файле записей (record). Следовательно объявить их просто полями как:

Код

type

TPersona = class
fName:String[20];
fHeal:Integer;
fLovkost:Integer;
...
...
...

end;


Представляется невозможным, так как, все поля должны сохраняться в одной записи (файла). Можно решить дело так:

Код

type
AllParametres = record //Описываем запись.
fName:String[20];
fHeal:Integer;
fLovkost:Integer;
...
...
...
end;

и дальше включить эту запись в класс:

type 

TPersona = class


fParametres: AllParametres;
...
...
...
end;




Но это представляется мне тоже довольно неудобным. Тем более что класса в программе три (базовый класс Сущность и его наследники Персонаж и Монстр). И все они отличаются количеством полей. 

При работе с файлами есть ли разница используем ли FileStream или стандартные команды: (Write Reset)?



Это сообщение отредактировал(а) PsiMagistr - 8.6.2010, 12:48


--------------------
"Арфы нет? Возьмите бубен!

Ребята, будем жить!"

 (с) "В бой идут одни старики"

---

"ИЕ" - один из самых сумасшедших браузеров в нашей галактике.
PM MAIL   Вверх
CodeMonkey
Дата 8.6.2010, 13:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1839
Регистрация: 24.6.2008
Где: Россия, Тверь

Репутация: 29
Всего: 89



Вообще-то, для классов нет нужды использовать записи. Вы можете сделать поля, которые хотите сохранять, published и сохранять в поток (TStream, в частности - TFileStream) обычными средствами. Класс при этом должен наследоваться от TPersistent.


--------------------
Опытный программист на C++ легко решает любые не существующие в Паскале проблемы.
PM MAIL WWW ICQ Skype GTalk Jabber   Вверх
PsiMagistr
Дата 8.6.2010, 14:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 479
Регистрация: 31.12.2009

Репутация: 1
Всего: 1



Да? Это интересно. А поподробней, если можно? Как сохранить через объект класса TFileStream запись, представляю. А вот поля класса...

Наткнулся на умную статью:

http://forum.vingrad.ru/topic-94245/view-all.html

Но к сожалению понял мало что...





Это сообщение отредактировал(а) PsiMagistr - 8.6.2010, 14:28


--------------------
"Арфы нет? Возьмите бубен!

Ребята, будем жить!"

 (с) "В бой идут одни старики"

---

"ИЕ" - один из самых сумасшедших браузеров в нашей галактике.
PM MAIL   Вверх
Rennigth
Дата 8.6.2010, 14:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Участник Клуба
Сообщений: 1708
Регистрация: 21.6.2004
Где: Moscow

Репутация: 15
Всего: 76



Цитата(PsiMagistr @  8.6.2010,  14:24 Найти цитируемый пост)
Но к сожалению понял мало что...

А что конкретно не понятно? Вроде там все с примерами...

Это сообщение отредактировал(а) Rennigth - 8.6.2010, 14:43


--------------------
(* Honesta mors turpi vita potior *)
PM MAIL ICQ   Вверх
PsiMagistr
Дата 8.6.2010, 14:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 479
Регистрация: 31.12.2009

Репутация: 1
Всего: 1



Пример хорош, но... Слишком много тонкостей. 

Цитата:

"модуль для сохранения и чтения объектов". 

 (Почему именно объектов, а не данных полей класса? Что значит сохранить объект? Голова кругом от научной терминологии)

Что есть: TWriter, TReader. Как они работают? 

И подробней о теории потоков (TStream).

Кроме того у меня должен быть именно файл записей. И каждая запись в файле - индивидуальный набор параметров. 



Это сообщение отредактировал(а) PsiMagistr - 8.6.2010, 15:41


--------------------
"Арфы нет? Возьмите бубен!

Ребята, будем жить!"

 (с) "В бой идут одни старики"

---

"ИЕ" - один из самых сумасшедших браузеров в нашей галактике.
PM MAIL   Вверх
PsiMagistr
Дата 8.6.2010, 17:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 479
Регистрация: 31.12.2009

Репутация: 1
Всего: 1



Смотрю статью. Ковыряюсь в коде примера. Что интересно: там процедуры записи-чтения объекта (полей) являются внешними. А мне бы их в класс встроить. Попробую завтра эксперимент сделать.

Это сообщение отредактировал(а) PsiMagistr - 8.6.2010, 18:18


--------------------
"Арфы нет? Возьмите бубен!

Ребята, будем жить!"

 (с) "В бой идут одни старики"

---

"ИЕ" - один из самых сумасшедших браузеров в нашей галактике.
PM MAIL   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Delphi: Для новичков"
SnowyMetalFan
bemsPoseidon
Rrader

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Литературу по Дельфи обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь
  • 90% ответов на свои вопросы можно найти в DRKB (Delphi Russian Knowledge Base) - крупнейшем в рунете сборнике материалов по Дельфи


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Snowy, MetalFan, bems, Poseidon, Rrader.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Delphi: Для новичков | Следующая тема »


 




[ Время генерации скрипта: 0.2422 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.