Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Прочее";
Текущий архив: 2009.08.02;
Скачать: [xml.tar.bz2];

Вниз

FreeAndNil против Free. Интересная концепция.   Найти похожие ветки 

 
Юрий Зотов ©   (2009-06-02 19:04) [80]

> А теперь вопрос, где у меня техническая ошибка кодинга?

Ошибка не лично Ваша, но для проекта это роли не играет. Вот она:
var
 SuperPuperForm: TSuperPuperForm;

Остальное - это уже следствия.

Модуль писал не профи. Модуль писал чайник. И запросто может оказаться, что это не единственная и не самая серьезная его плюха.

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

===========

PS
Но Ваш пример к сабжу не относится. В Вашем случае что бы там у него ни стояло - хоть Free, хоть FreeAndNil - результат один и тот же.


 
Ганя   (2009-06-02 19:35) [81]


> Юрий Зотов ©   (02.06.09 19:04) [80]


> Ошибка не лично Ваша, но для проекта это роли не играет.
>  Вот она:
> var
>  SuperPuperForm: TSuperPuperForm;


Такой код вроде как генерируется средой. Считаете. что оставление глобальной переменной - преступление?) а как быть с главной формой?


 
clickmaker ©   (2009-06-02 19:42) [82]

> а как быть с главной формой?

главную форму крайне редко создают на лету в процессе работы, и она живет все время жизни программы.
Так же как и Application, Screen и другие глобальные переменные.
Так что, ей можно )


 
Юрий Зотов ©   (2009-06-02 19:52) [83]

> Ганя   (02.06.09 19:35) [81]

> Такой код вроде как генерируется средой.

Угу. Что не есть хорошо, потому что способствует привитию плохих навыков начинающим. Как и AutoCreate (кстати, ведь только из-за AutoCreate эти переменные и генерятся).

> Считаете. что оставление глобальной переменной - преступление?

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

> а как быть с главной формой?

Главная - она главная и есть. Для нее можно сделать исключение. Но еще лучше было бы, если бы метод Application.CreateForm назывался CreateMainForm, позволял создавать только главную форму и имел только один параметр - класс формы. Тем более, что ссылка на созданный им экземпляр главной формы все равно запоминается в Application.MainForm и никакие дополнительные переменные уже не нужны.


 
asails   (2009-06-02 20:38) [84]


> Игорь Шевченко ©   (02.06.09 16:07) [79]


> Я тебе Access Violation устрою мигом

Верю охотно. А как сам разруливаешь? Лично я считаю, что (по возможности) убивать объект надо там-же где и создали. Хотя, могут быть и исключения. В случае Action := caFree, единственное решение, которое пришло в голову - это вообще не вызывать Free, а выставлять Owner"а. Например, так:
with TSuperPuperForm.Create(Self) do
ShowModal;
И усе.
Я таки думаю, что caFree надо всячески избегать.


 
Игорь Шевченко ©   (2009-06-02 21:01) [85]

Юрий Зотов ©   (02.06.09 19:52) [83]


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


Нафига ?

asails   (02.06.09 20:38) [84]


> Верю охотно. А как сам разруливаешь?


Не делаю Free :)


> Лично я считаю, что (по возможности) убивать объект надо
> там-же где и создали


Немодальные формы, например, так не убъешь.


 
Юрий Зотов ©   (2009-06-02 21:05) [86]

> Игорь Шевченко ©   (02.06.09 21:01) [85]

Чтобы сразу исключить подобные ситуации.


 
Игорь Шевченко ©   (2009-06-02 21:10) [87]

Юрий Зотов ©   (02.06.09 21:05) [86]


> Чтобы сразу исключить подобные ситуации.


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


 
Юрий Зотов ©   (2009-06-02 21:16) [88]

> Игорь Шевченко ©   (02.06.09 21:10) [87]

> профи в такую ситуацию не попадут.

Угу. Но завтра профи уволится и этот код полезет править кто-нибудь другой.

> А вот если форма должна быть создана один раз

Если в ней действительно есть постоянная нужда в течение всего времени работы приложения, то ее надо делать синглтоном, убирать глобальную ссылку в implementation, а в interface делать фунцию GetMyForm.

А если она болтается просто так, то памяти жалко.


 
asails   (2009-06-02 21:22) [89]


> Игорь Шевченко ©   (02.06.09 21:01) [85]


> Не делаю Free :)

Т.е. терпеливо ждешь, пока Owner не умрет? И все это время память занята уже никому не нужными объектами. А если Owner долго не умирает, а объекты все создаются и создаются? Взгляни, например, на элементарный ShowMessage (MessageDlgPosHelp):

with CreateMessageDialog(Msg, DlgType, Buttons) do
   try
     HelpContext := HelpCtx;
     HelpFile := HelpFileName;
     if X >= 0 then Left := X;
     if Y >= 0 then Top := Y;
     if (Y < 0) and (X < 0) then Position := poScreenCenter;
     Result := ShowModal;
   finally
     Free;
   end;


Ведь тоже можно Free не вызывать. Умрут вместе с владельцем - Application. Только нафига ими память засорять на протяжении всей жизни приложения? Не кошерно как-то...


 
Игорь Шевченко ©   (2009-06-02 21:29) [90]

Юрий Зотов ©   (02.06.09 21:16) [88]


> Если в ней действительно есть постоянная нужда в течение
> всего времени работы приложения, то ее надо делать синглтоном,
>  убирать глобальную ссылку в implementation, а в interface
> делать фунцию GetMyForm.


проще надо быть.


> Но завтра профи уволится и этот код полезет править кто-
> нибудь другой.


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

asails   (02.06.09 21:22) [89]


> Т.е. терпеливо ждешь, пока Owner не умрет?


Нет, ставлю в OnClose Action := caFree :)


 
asails   (2009-06-02 21:51) [91]


> Игорь Шевченко ©   (02.06.09 21:29) [90]


> Нет, ставлю в OnClose Action := caFree :)

А если подразумевается, что форма может пригодиться и после закрытия? Например, в вызвавшем ее коде надо прочитать значения каких-нибудь свойств. Тогда, я так понимаю, caFree не ставишь? И теперь при показе той или иной формы надо думать, а есть ли там caFree или так убивать?
Это тоже вариант, но мне проще (или привычней?) Free, чем caFree. Вот для не модальных форм можно и caFree при закрытии. А можно и просто Release. Я, если честно, вообще без Action := caFree обходился как-то. :)


 
Игорь Шевченко ©   (2009-06-02 22:08) [92]

asails   (02.06.09 21:51) [91]


> А если подразумевается, что форма может пригодиться и после
> закрытия?


Тогда не ставлю :)


> Это тоже вариант, но мне проще (или привычней?) Free, чем
> caFree.


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


> Вот для не модальных форм можно и caFree при закрытии


Собственно, не можно, а нужно.


> А можно и просто Release.


В каком месте ?


> Я, если честно, вообще без Action := caFree обходился как-
> то. :)


Я где-то в примерах увидел 14 лет назад - понравилось :)


 
Ганя   (2009-06-02 22:12) [93]

тогда можно одной строкой создавать и показывать :-)

TMyForm.Create(Self).ShowModal;


 
Юрий Зотов ©   (2009-06-02 22:13) [94]

> Игорь Шевченко ©   (02.06.09 21:10) [87]

1. > если форма должна быть создана один раз, то с объявленной средой
> переменной жить становится гораздо проще.

2. > Нет, ставлю в OnClose Action := caFree :)

Одно противоречит другому. Как понять тебя, Саид?


 
Игорь Шевченко ©   (2009-06-02 22:21) [95]

Юрий Зотов ©   (02.06.09 22:13) [94]


> Одно противоречит другому. Как понять тебя, Саид?


Это разные формы :)


 
Юрий Зотов ©   (2009-06-02 22:58) [96]

> Игорь Шевченко ©   (02.06.09 22:21) [95]

Ну слава Богу. Но есть еще один момент - а насколько хорошо удобная (как ты говоришь) глобальная переменная сочетается с caFree?

Или это тоже разные формы?


 
Юрий Зотов ©   (2009-06-02 23:01) [97]

Видимо, разные. Но тогда получается, что искомая глобальная переменная вовсе не так уж и удобна. Даже для резидентных форм (потому что она не ReadOnly).


 
Игорь Шевченко ©   (2009-06-02 23:02) [98]

Юрий Зотов ©   (02.06.09 22:58) [96]


> а насколько хорошо удобная (как ты говоришь) глобальная
> переменная сочетается с caFree?


Для таких форм (заметь, только для таких, которые не должны повторно создаваться, а должны показываться уже созданные), глобальная переменная в событии OnDestroy приравнивается к nil.

То есть, глобальная переменная служит тем, для она была предназначена - хранение указателя на созданную (ну или еще не созданную) форму.


 
Игорь Шевченко ©   (2009-06-02 23:07) [99]

Юрий Зотов ©   (02.06.09 23:01) [97]


> Но тогда получается, что искомая глобальная переменная вовсе
> не так уж и удобна


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

то есть, конструкция

procedure TfMain.ShowSomeForm;
begin
 if not Assigned(fSomeForm) then
   fSomeForm := TFSomeForm.Create(Application или Self);
 fSomeForm.Show;
end;

и
unit SomeForm;

...

type
 TfSomeForm = class(TAncestorForm)
 ...
   procedure FormDestroy (Sender: TObject);
 ...
 end;

var
 fSomeForm: TfSomeForm;
...

procedure FormDestroy (Sender: TObject);
begin
 inherited;
 fSomeForm := nil;
end;

оказалась проста, удобна, и главное, понятна.


 
Юрий Зотов ©   (2009-06-02 23:40) [100]

> Игорь Шевченко ©   (02.06.09 23:07) [99]

То есть, ровно тот же самый синглтон, только:

1. Не проще обычного.
2. Менее удобный (потому что реализован не компактно, код разбросан минимум по двум модулям).
3. Гарантирующий утечки памяти, если какой-нибудь чудак, не знающий особенностей реализации, в своем модуле вдруг напишет fSomeForm := nil.


 
Игорь Шевченко ©   (2009-06-02 23:47) [101]

Юрий Зотов ©   (02.06.09 23:40) [100]


> 1. Не проще обычного.


Проще. Ничего не надо писать.


> 2. Менее удобный (потому что реализован не компактно, код
> разбросан минимум по двум модулям).


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


> 3. Гарантирующий утечки памяти, если какой-нибудь чудак,
>  не знающий особенностей реализации, в своем модуле вдруг
> напишет fSomeForm := nil.


Это я вообще не комментирую - если кто-то кое-где у нас порой...


 
Юрий Зотов ©   (2009-06-02 23:51) [102]

В то время как вот такая конструкция

unit SomeForm;

interface

type
 TfSomeForm = class(TAncestorForm)
   procedure FormDestroy(Sender: TObject);
 end;

function fSomeForm(AOwner: TComponent): TfSomeForm;

implementation

var
 _fSomeForm: TfSomeForm;

function fSomeForm: TfSomeForm;
begin
 if not Assigned(_fSomeForm) then
   _fSomeForm := TfSomeForm.Create(AOwner);
 Result := _fSomeForm
end;

procedure FormDestroy(Sender: TObject);
begin
 inherited;
 _fSomeForm := nil
end;

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


 
Юрий Зотов ©   (2009-06-02 23:55) [103]

> Ничего не надо писать.

Я написал практически твой же код. Почти буква в букву. Но лучше.

> почему стандартный дизайнер форм генерирует глобальную переменную
> типа формы в интерфейсной части? Аккурат вот для этого самого
> использования минимум в двух модулях.

Нет, Игорь, не для этого. Аккурат для AutoCreate. Чтобы вставить в dpr строчку с Application.CreateForm.


 
DVM ©   (2009-06-03 00:18) [104]


> Аккурат для AutoCreate. Чтобы вставить в dpr строчку с Application.
> CreateForm.

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


 
Игорь Шевченко ©   (2009-06-03 00:33) [105]

Юрий Зотов ©   (02.06.09 23:51) [102]


> не менее проста и понятна, чем твоя, реализует точно такую
> же функциональность (именно не синглтон, а точно такую же),
>  но при этом удобнее


И это проходили.
Неудобнее - писать больше.


> Нет, Игорь, не для этого. Аккурат для AutoCreate. Чтобы
> вставить в dpr строчку с Application.CreateForm.


Да-да. А это конечно не в двух модулях.


> и обладает одним замечательным свойством - защитой от дурака.


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


 
Игорь Шевченко ©   (2009-06-03 00:34) [106]

DVM ©   (03.06.09 00:18) [104]


> Непонятно, почему разработчики VCL сделали метод CreateForm
> именно таким


Сдуру очевидно.


>  Сделали бы только с именем класса формы и не нужна была
> бы глобальная переменная.


А ссылаться на экземпляр ?


 
DVM ©   (2009-06-03 00:41) [107]


> Игорь Шевченко ©   (03.06.09 00:34) [106]


> А ссылаться на экземпляр ?

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


 
Petr V. Abramov ©   (2009-06-03 00:47) [108]


> у объекта Application можно было хранить список созданных
> форм,

у Application есть components и Forms, если у меня не маразм.


 
Игорь Шевченко ©   (2009-06-03 00:48) [109]

DVM ©   (03.06.09 00:41) [107]

И нафига такие извраты ? (Ты меня извини конечно, но если человек задался целью навредить в коде, он это сделает и без глобальных переменных).


> у объекта Application можно было хранить список созданных
> форм, для прочих объект Application мог этот список  сделать
> доступным.


Собственно, хранится, только не у Application, а у Screen, и вполне доступный. Screen.Forms называется.
Когда надо из какого-то невообразимого места добраться до некой формы  и послать ей сообщение, метод поиска среди Screen.Forms вполне нормальная альтернатива явной ссылке на переменную с этой формой.


 
DVM ©   (2009-06-03 01:00) [110]


> Petr V. Abramov ©


> у Application есть components и Forms, если у меня не маразм.

У Screen есть список форм.


> Игорь Шевченко ©   (03.06.09 00:48) [109]


> И нафига такие извраты ? (Ты меня извини конечно, но если
> человек задался целью навредить в коде, он это сделает и
> без глобальных переменных).

Да просто так, вроде бы логично было, если бы в программе была одна глобальная переменная Application.
Я ж не против глобальных переменных, я их наоборот тут как то защищал в одной из веток.


 
Юрий Зотов ©   (2009-06-03 01:20) [111]

> Игорь Шевченко ©   (03.06.09 00:33) [105]

> Неудобнее - писать больше.

Сравни 2 кода. Больше ровно на одну короткую строчку - объявление функции в interface. Все остальное - один к одному Зато имеем защиту от дурака, а она стоит гораздо дороже одной строчки.

> Я не комментирую защиту от дураков

А зря. Защита от дурака - это тоже одна из составляющих стиля кодинга профессионала.

> DVM ©   (03.06.09 00:41) [107]

> обойтись без глобальной переменной можно было

Можно. Ссылка на главную форму и так хранится (Application.MainForm), а ссылки на остальные формы нужны только для AutoCreate. Убираем AutoCreate - и эти ссылки становятся необязательными. Если программеру такие глобальные переменные нужны - он их сам заведет, не проблема.


 
Petr V. Abramov ©   (2009-06-03 01:30) [112]


> Юрий Зотов ©   (03.06.09 01:20) [111]
> А зря. Защита от дурака - это тоже одна из составляющих
> стиля кодинга профессионала.

позвольте вмешаться в вашу Игорем высокоумную беседу. Одно из прямых следствий одного из подмножества законов Мэрфи гласит: если будет создана программа с полной защитой от дурака, то только полный дурак и будет таковой программой пользоваться.
:)


 
Игорь Шевченко ©   (2009-06-03 01:33) [113]

Юрий Зотов ©   (03.06.09 01:20) [111]


> Сравни 2 кода. Больше ровно на одну короткую строчку - объявление
> функции в interface.


Строчки будем считать ? Вовсе не на одну, но это мелочь.

В моем случае руками надо писать ровно 4 строчки (три при вызове и одну в FormDestroy).


> А зря. Защита от дурака - это тоже одна из составляющих
> стиля кодинга профессионала.


Ты полагаешь, среду и VCL писали настолько непрофессионалы ? Странно, я был об авторах Delphi более высокого мнения.


 
Юрий Зотов ©   (2009-06-03 01:56) [114]

> Игорь Шевченко ©   (03.06.09 01:33) [113]

> Ты полагаешь, среду и VCL писали настолько непрофессионалы ? Странно,
> я был об авторах Delphi более высокого мнения.

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

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

Еще я обратил внимание на твой код:
procedure FormDestroy (Sender: TObject);
begin
 inherited;
 fSomeForm := nil;
end;

и вспомнил твои же совсем недавние слова: см. [19].

На сим пошел спать.


 
Petr V. Abramov ©   (2009-06-03 02:09) [115]


> но не учли, что многие из тех, кто этим удобством будет
> пользоваться, достаточной для ее грамотного использования
> квалификацией не обладают.

учли. галка соотв. есть.


 
Игорь Шевченко ©   (2009-06-03 02:25) [116]

Юрий Зотов ©   (03.06.09 01:56) [114]


> Еще я полагаю, что вопрос абсолютно ясен и прения на тему
> "из пустого в порожнее" можно прекратить. Если ты не считаешь,
>  что код должен быть как можно более надежным - дело твое.


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


> Еще я обратил внимание на твой код:
> procedure FormDestroy (Sender: TObject);
> begin
>  inherited;
>  fSomeForm := nil;
> end;
> и вспомнил твои же совсем недавние слова: см. [19].


Извини, но совсем мимо. Ну то есть, совсем.


 
Юрий Зотов ©   (2009-06-03 03:51) [117]

> Игорь Шевченко ©   (03.06.09 02:25) [116]

Угу, совсем мимо. В унаследованном обработчике возникает исключение - и переменная не обнуляется. После чего вся логика летит совсем мимо. С непредсказуемыми результатами.

PS
Блин. Не спится.


 
Юрий Зотов ©   (2009-06-03 04:00) [118]

> Petr V. Abramov ©   (03.06.09 02:09) [115]

> галка соотв. есть.

А толку? Ну, убрал ты эту галку (она у меня по жизни убрана) - и что? Переменные-то все равно генерятся.


 
Юрий Зотов ©   (2009-06-03 04:18) [119]

> код должен быть как можно более простым при заданной
> функциональности.

И еще надежным. Иначе он практически бесполезен.

> Ненадежности в своем примере я не вижу.

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

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

А таких мест просто не должно быть.


 
Игорь Шевченко ©   (2009-06-03 10:56) [120]

Юрий Зотов ©   (03.06.09 04:18) [119]


> Угу, совсем мимо. В унаследованном обработчике возникает
> исключение - и переменная не обнуляется. После чего вся
> логика летит совсем мимо. С непредсказуемыми результатами.
>


А с чего ему возникать ?



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

Форум: "Прочее";
Текущий архив: 2009.08.02;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.71 MB
Время: 0.009 c
15-1243629004
Юрий
2009-05-30 00:30
2009.08.02
С днем рождения ! 30 мая 2009 суббота


3-1225220926
kile
2008-10-28 22:08
2009.08.02
sql server, оператор output и adoDataSet


3-1225144232
Раиса
2008-10-28 00:50
2009.08.02
MySQL и SSH Tunneling - какие компоненты


2-1244117526
b/@.
2009-06-04 16:12
2009.08.02
Можно ли объекту уничтожить самого себя ?


4-1213778010
incm
2008-06-18 12:33
2009.08.02
Как в главном окне перехватывать сообщения WM_MDICREATE и т.п.





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