Странность при создании и удалении объекта.

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

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

Странность при создании и удалении объекта.

Сообщение Konung » 18.06.2013 12:59:50

пишем что то вроде:

Код: Выделить всё
var
  fs:TFileStreamUTF8;
begin
try
fs:=TFileStreamUTF8.Create(FileName, fmOpenRead or fmShareDenyNone);
finally
if Assigned(fs) then
  fs.free;
end;
end;


при трейсе. на строке fs:= (т.е. сама срока еще не выполнилась) среда показывает что там уже вроде как есть объект. хотя должен быть nil насколько я понимаю.
далее - при открытии возникает ошибка (не верное имя файла). по идее - fs должен был быть остаться nil. но проверяю на всяк случ if Assigned(fs) - и объект есть. но сделать ему free - не выходит. вываливатеся в ошибку.
Кто нить сталкивался? отчего так? почему до создания объект уже есть? отчего убедившись что объект есть и пытаясь сделать ему free - ошибка?

заранее благодарю за ответы.
Konung
новенький
 
Сообщения: 16
Зарегистрирован: 19.11.2011 02:46:24

Re: Странность при создании и удалении объекта.

Сообщение VirtUX » 18.06.2013 13:43:14

Могу ошибаться, но неинициализированная переменная явно, всегда указывает на какой-то адрес. А по этому адресу всегда что-то есть. Т.ч. fs станет равным nil только после явного fs := nil;

Добавлено спустя 42 секунды:
Konung писал(а):var
fs:TFileStreamUTF8;
begin
fs := nil; // явная инициализация
try
fs:=TFileStreamUTF8.Create(FileName, fmOpenRead or fmShareDenyNone);
finally
if Assigned(fs) then
fs.free;
end;
end;


Добавлено спустя 3 минуты 54 секунды:
функция Assigned проверяет является ли указатель nil. Если не nil, то возвращает True; если nil, то False
взято от сюда. От сюда следуют все Ваши проблемы ;)
Аватара пользователя
VirtUX
энтузиаст
 
Сообщения: 880
Зарегистрирован: 05.02.2008 10:52:19
Откуда: Крым, Алушта

Re: Странность при создании и удалении объекта.

Сообщение Konung » 18.06.2013 14:17:58

гм... т.е. всегда надо делать в таких случаях :=nil ?
странно, в дельфе вроде всегда такие фокусы проходили без принудительного "зануления".

ммм... буду тестить...
Konung
новенький
 
Сообщения: 16
Зарегистрирован: 19.11.2011 02:46:24

Re: Странность при создании и удалении объекта.

Сообщение SeZuka » 18.06.2013 14:20:13

Раз не было инициализации переменной, то в ней может быть любой "мусор", проще сделать так:
Код: Выделить всё
var
fs:TFileStreamUTF8 = nil;
begin


И еще у вас конструкция finally неправильно сделана, от этого и проблемы :)
Правильный код должен быть таким:
Код: Выделить всё
var
  fs:TFileStreamUTF8;
begin
fs:=TFileStreamUTF8.Create(FileName, fmOpenRead or fmShareDenyNone);
try
   // код обработки
finally
  fs.free;
end;
end;

Если при открытии произойдет исключение, то и fs не создастся и удалять его не нужно (просто произойдет выход из вашей процедуры), а вот если он создался, то тут и сработает finally в любом случае.
SeZuka
постоялец
 
Сообщения: 209
Зарегистрирован: 05.09.2012 14:58:05

Re: Странность при создании и удалении объекта.

Сообщение Konung » 18.06.2013 14:31:36

SeZuka писал(а):Раз не было инициализации переменной, то в ней может быть любой "мусор", проще сделать так:
Код: Выделить всё
var
fs:TFileStreamUTF8 = nil;
begin



угу... ну это чисто конструктивно проще... я так понимаю - в дельфе это "зануление" было как бы по дефолту? может и в фрипасе/лазаре это можно опционально включить?

SeZuka писал(а):И еще у вас конструкция finally неправильно сделана, от этого и проблемы :)
Правильный код должен быть таким:
...
fs:=TFileStreamUTF8.Create(FileName, fmOpenRead or fmShareDenyNone);
try
...


гм... если я правильно понимаю, то в таком случае если, например, файла нет - то на fs:= я получу ошибку и работа процедуры прервется. до последующих try... просто не дойдет и обработать ошибку я тут не смогу.
а ставя за try - будет или не ошибка, но выполнится блок finally. в коем я могу (если надо) обработать ошибку и удалить объект если он есть.
дело в том что это пример... и в случпе отсутствия файла, или иной ошибки его открытия мне надо проделать еще ряд действий.
Konung
новенький
 
Сообщения: 16
Зарегистрирован: 19.11.2011 02:46:24

Re: Странность при создании и удалении объекта.

Сообщение SeZuka » 18.06.2013 15:29:49

Если вам не надо вываливаться из процедуры, то оберните все это в блок try .. except .. end при возникновении ошибки (и только в случае ошибки) попадете в блок except где обработаете ее и дальше пойдет выполнение того что идет после end. А конструкция try .. finally .. end не предназначена для обработки исключений, она предназначена для выполнения каких-либо действий в любом случае, не зависимо от того произошло исключение или нет. И кстати если конструкция finally не была обернута в конструкцию except, то при возникновении исключения после обработки в блоке finally произойдет выход из процедуры, без выполнения дальнейших операторов.
SeZuka
постоялец
 
Сообщения: 209
Зарегистрирован: 05.09.2012 14:58:05

Re: Странность при создании и удалении объекта.

Сообщение stanilar » 19.06.2013 11:09:37

Konung писал(а): в случае отсутствия файла, или иной ошибки его открытия мне надо проделать еще ряд действий


В Delphi использую такой код:

Код: Выделить всё
try
  try
    fs:=TFileStreamUTF8.Create(FileName, fmOpenRead or fmShareDenyNone);
  except
    Exit;
  end;
  fs.Free;
  ...
finally
  ...
end;
stanilar
постоялец
 
Сообщения: 289
Зарегистрирован: 09.03.2010 19:09:02

Re: Странность при создании и удалении объекта.

Сообщение Ism » 19.06.2013 15:38:04

Есть такая функция FreeAndNil ,
Она делает
.free
:=nil

FreeAndNil удобней, она не выдает ошибки если объект уже пустой

Так рекомендуют делать
http://www.gunsmoker.ru/2009/04/freeandnil-free.html
Ism
энтузиаст
 
Сообщения: 908
Зарегистрирован: 06.04.2007 17:36:08

Re: Странность при создании и удалении объекта.

Сообщение Konung » 19.06.2013 16:02:41

2 SeZuka & stanilar
сенкс. что то я то ли забыл то ли не подумал что finally не обработает исключение. терь понятнее с этим.

2 Ism
эт я в курсе. тут писал для примера. обычно как раз и юзаю freeandnil. но вопрос в другом был. что при инициализации - объекта вроде нет, но он не нил. а на что то ссылается - и отсюда - глюк мой.
Konung
новенький
 
Сообщения: 16
Зарегистрирован: 19.11.2011 02:46:24

Re: Странность при создании и удалении объекта.

Сообщение VirtUX » 20.06.2013 07:00:05

Konung писал(а):т.е. всегда надо делать в таких случаях :=nil ?

Скажу более: любая переменная неинициализированная явно, будет содержать бяку!
Для примера:
Что будет написано в метке?
Код: Выделить всё
var
  i:integer;
begin
  Label.Caption := IntToStr(i);
end;

А теперь еще раз перезапустите программу...
И каждый раз Вы будете иметь непредвиденный результат ;)
Аватара пользователя
VirtUX
энтузиаст
 
Сообщения: 880
Зарегистрирован: 05.02.2008 10:52:19
Откуда: Крым, Алушта

Re: Странность при создании и удалении объекта.

Сообщение Konung » 20.06.2013 12:03:08

2 VirtUX
с переменными я в курсе. хотя, если уж совсем общё, - перемнная типа стринг будет всегда пуста.
я к тому, что по дельфевой привычке привык считать что объекты по объявлению занулены.

и я так понимаю что в общем случае - узнать какими либо методами есть ли живой объект - я не могу?
Konung
новенький
 
Сообщения: 16
Зарегистрирован: 19.11.2011 02:46:24

Re: Странность при создании и удалении объекта.

Сообщение VirtUX » 20.06.2013 16:24:51

Konung писал(а):перемнная типа стринг будет всегда пуста

String - это как бы динамический массив. Поэтому он при объявлении нулевой. И только при инициализации распределяется в памяти.
Konung писал(а): узнать какими либо методами есть ли живой объект - я не могу?

Код: Выделить всё
if Assigned(obj) then ...;

Проверяет объектную переменную на nil. Единственное, что нужно не забывать после объявления инициализировать объект: либо obj := nil; либо obj := TAnyObject.Create;
Если до проверки Вы не инициализируете объект, то какой смысл его проверять? Если объект объявляли не Вы, то "минус в карму" тому, кто забыл его инициализировать ;) Не знаю как там в Delphi, но я бы даже и там не забывал инициализировать вручную... ИМХО
Аватара пользователя
VirtUX
энтузиаст
 
Сообщения: 880
Зарегистрирован: 05.02.2008 10:52:19
Откуда: Крым, Алушта

Re: Странность при создании и удалении объекта.

Сообщение alexey38 » 20.06.2013 19:28:34

В Дельфях при запуске равны 0 только глобальные переменные. Локальные по-моему не чистятся. Кроме элементов со счетчиками ссылок, типа строк, массивов и интерфейсов.
alexey38
долгожитель
 
Сообщения: 1627
Зарегистрирован: 27.04.2011 19:42:31

Re: Странность при создании и удалении объекта.

Сообщение pda » 23.06.2013 00:36:27

Чтение документации (к Delphi) и знание истории Borland Pascal помогут пролить свет на ситуацию. Изначально pascal работал на очень медленных машинах, где для экономии места и ускорения запуска переменные не инициализировались и по умолчанию содержали мусор. В дальнейшем эта особенность осталась, потому что была документирована.
Однако, позднее, Borland (уже в Delphi) добавил классы и динамические типы, типа длинных строк (превратившихся в Ansi/Wide/UnicodeString) и динамических массивов. Процессоры в это время стали достаточно быстрыми, чтобы экономия на спичках имела смысл. По этому поля классов очищаются при создании экземпляра, а строки и массивы инициализируются.

Что же касается приведённого кода, то он не правильный. Надо писать так:
Код: Выделить всё
fs:=TFileStreamUTF8.Create(FileName, fmOpenRead or fmShareDenyNone);
try
  <...>
finally
  FreeAndNil(fs);
end;

Почему так? Потому что необработанное исключение в конструкторе приводит к вызову деструктора. Соответственно, засовывать .Create() в try/finally нет никакого смысла. Я не проверял исходники Free Pascal, но подозреваю, что там аналогичная реализация. В противном случае - стыд и позор на разработчиков. :)
Аватара пользователя
pda
постоялец
 
Сообщения: 303
Зарегистрирован: 27.05.2005 19:59:53


Вернуться в Free Pascal Compiler

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 1

Рейтинг@Mail.ru