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

Вниз

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

 
Дмитрий Белькевич   (2009-05-29 12:47) [0]

Наткнулся на интересную статью:

http://gunsmoker.blogspot.com/2009/04/freeandnil-free.html

Посему хочу спросить - насколько автор прав? Действительно ли Free можно поменять везде на FreeAndNil? Можно ли придумать пример, где это будет работать неверно?

В целях развития идеи могу предложить следующее. Заменить глобально TObject.Free на вызов FreeAndNil (в тестовых целях, или перманентно). Плюсы такого подхода:

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

Поменять, я думаю, можно так, как это делает RtlVclOptimize:

CodeRedirect(GetActualAddr(@System.LoadResString), @LoadResString);

Попробовал у себя в одном проекте поменять все вызовы Free на FreeAndNil. Ничего страшного не произошло. Массового падения не было, утечек тоже. Нашел место, где был доступ до рузрушенного объекта. Так что польза от такой замены определенно может быть.


 
TUser ©   (2009-05-29 12:56) [1]

Можно сделать так, что FreeAndNil даже не скомпилиться :)

type
TGluk = class
  procedure GlukProc;
  end;

procedure TGluk.GlukProc;
begin
 ShowMessage ("I""m gluk");
end;

procedure ShowGluk (const Gluk: TGluk);
begin
 Gluk.GlukProc;
 // Gluk.Free;
 FreeAndNil (Gluk);
end;

procedure TForm1.Button1Click(Sender: TObject);
var G: TGluk;
begin
 G := TGluk.Create;
 G.GlukProc;
end;


 
Ega23 ©   (2009-05-29 12:58) [2]

Знаешь, у меня вообще нигде FreeandNil нету. Вообще нигде. И ничего.


 
Игорь Шевченко ©   (2009-05-29 13:06) [3]


> Действительно ли Free можно поменять везде на FreeAndNil?
>  


нет конечно. FreeAndNil принимает var-параметр


 
Игорь Шевченко ©   (2009-05-29 13:10) [4]


> http://gunsmoker.blogspot.com/2009/04/freeandnil-free.html


"Другое дело, что сам with страшен. Вам не следует использовать его".

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


 
Дмитрий Белькевич   (2009-05-29 13:10) [5]

>Можно сделать так, что FreeAndNil даже не скомпилиться :)

Плюс подхода автора в том, что придётся заодно от потенциально опасных мест типа [1] избавляться.


 
Дмитрий Белькевич   (2009-05-29 13:13) [6]


> нет конечно. FreeAndNil принимает var-параметр


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

То, что FreeAndNil с const не соберется - я знаю.


 
Игорь Шевченко ©   (2009-05-29 13:20) [7]

Дмитрий Белькевич   (29.05.09 13:10) [5]

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

Особенно умиляет наличие такого кода:

type
 TFoo = class
 private
    FBar: TBar;
 ..
 public
    constructor Create;
    destructor Destroy; override;
 end;

constructor TFoo.Create;
begin
 Fbar := TBar.Create;
 ...
end;

destructor TFoo.Destroy;
begin
  ...
  FreeAndNil(FBar);
  inherited;
end;


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


 
Ганя   (2009-05-29 13:35) [8]


> Игорь Шевченко ©   (29.05.09 13:20) [7]



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


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

Но вообще конечно такое обобщение -  "всегда использовать FreeAndNil вместо Free" - глупость


 
Ega23 ©   (2009-05-29 13:37) [9]


> такое может быть - из inherited Destoy - в предке дергается
> виртуальный метод, который в потомке переопределен с обращением
> к FBar


На такие исключительные случаи можно написать
 FBar.Free;
 FBar := nil;


 
Игорь Шевченко ©   (2009-05-29 13:42) [10]

Ганя   (29.05.09 13:35) [8]


> в предке дергается виртуальный метод, который в потомке
> переопределен с обращением к FBar
> вот и приплыли.


Куда приплыли ?

FBar - private, о каких потомках может идти речь ? :)


 
KSergey ©   (2009-05-29 13:51) [11]

меня аргументы автора не убедили. Хотя то, что использовать FreeAndNil не ухудшит ситуацию - это да.


 
jack128_   (2009-05-29 13:51) [12]


> Куда приплыли ?

ты не понял.

TFooAncestor = class
protected
 procedure DoWork; virtual; abstract;
public
 destructor Destroy; override;
end;

destructor TFooAncestor.Destroy;
begin
 DoWork;
end;

TFoo = class(TFooAncestor)
private
 FBar: TBar;
protected
 procedure DoWork; override;
public
 destructor Destroy; override;
end;

procedure TFoo.DoWork;
begin
 ShowMessage(FBar.Name); // Если уничтожаем FreeAndNil(FBar) - то ошибка всплывет сразу.  Если же уничтожать через FBar.Free - то не факт
end;

destructor TFoo.Destroy;
begin
 FBar.Free;
 inherited;
end;


 
Плохиш ©   (2009-05-29 13:52) [13]


> Игорь Шевченко ©   (29.05.09 13:42) [10]


> FBar - private, о каких потомках может идти речь ? :)

Он говорит о той породе горекодеров, которые не знают, что у них делается в соседних строках глюкокода ;-)


 
Игорь Шевченко ©   (2009-05-29 14:03) [14]

jack128_   (29.05.09 13:51) [12]

Видишь ли, Женя, программу на Фортране можно написать на любом языке программирования. Дальнейшую дискуссию на эту тему считаю нецелесообразной, так как количество способов написать глючную программу, обойдя любые ламерские рекомендации (не использовать with, использовать freeandnil вместо free, еще что-нибудь из подобной оперы), заведомо превышает количество способов написать неглючную программу.

Плохиш ©   (29.05.09 13:52) [13]

Таким принудительное выпрямление рук не поможет, только ампутация. Желательно по самую голову.


 
Ганя   (2009-05-29 17:20) [15]


> Игорь Шевченко ©   (29.05.09 14:03) [14]


> Видишь ли, Женя,


А что именно в приведенном куске кода выдает "программу на фортране"?
Сам по себе факт вызова виртуального метода в деструкторе?
Или имя виртуального метода "DoWork"?
Давай заменим его на Clear
или на Disconnect
Поясните, где тут фортранность и кривизна рук?


 
Игорь Шевченко ©   (2009-05-29 17:24) [16]


> А что именно в приведенном куске кода выдает "программу
> на фортране"?


Необходимость для корректной работы сначала вызывать унаследованный деструктор, а затем освобождать собственные объекты.


 
TUser ©   (2009-05-29 17:42) [17]

Вообще, FreeAndNil явно опирается на парадигму "один объект - один указатель", то есть объект у нас де-факто - статический. Что явно противоречит идее динамических объектов, приятой в Delphi. Имхо.

Иными словами, есть на Obj1 у меня только одна ссылка, то это хорошо. А вот если где-то хранится ссылка ...


 
Юрий Зотов ©   (2009-05-29 18:03) [18]

Если человек пишет код бездумно, то и FreeAndNil ему не поможет.

Да, есть такая рекомендация - в деструкторе класс сначала чистит свое, и только потом вызывает inherited. Но это же не закон? Нет. И обязанность думать не отменяет.

В данном случае разработчик класса TFoo должен был бы сначала хорошо ознакомиться с классом-предком (вообще, при разработке класса-потомка знать особенности класса-предка даже не желательно, а обязательно), а потом написать так:

destructor TFoo.Destroy;
begin
 inherited;  
 FBar.Free;
end;

И все проблемы.


 
Игорь Шевченко ©   (2009-05-29 18:23) [19]

Юрий Зотов ©   (29.05.09 18:03) [18]

Законы определяются исключительно грамматикой языка и средствами библиотеки времени выполнения. Других законов попросту не существует, все остальное - рекомендации, корпоративные стандарты, правила хорошего тона и т.п. :)


> destructor TFoo.Destroy;
> begin
>  inherited;  
>  FBar.Free;
> end;


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


 
Юрий Зотов ©   (2009-05-29 18:28) [20]

> Игорь Шевченко ©   (29.05.09 18:23) [19]

> destructor TFoo.Destroy;
> begin
>  inherited;  
>  FBar.Free;
> end;

> у меня при взгляде на подобный код возникают подозрения в
> компетентности автора.

Это лишь потому, что в момент этого взгляда ты забываешь о том, что:

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

(c) Игорь Шевченко.

:o)


 
SPeller ©   (2009-05-29 19:59) [21]

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


 
Нат ©   (2009-05-30 01:34) [22]

destructor TFoo.Destroy;
begin
inherited;  
FBar.Free;
end;

Припоминаю сообщение об утечках памяти при динамическом создании-удалении  TADOCommand. Именно по причине вызова inherited раньше прочего. Для сравнения, TAdoCustomDataSet вызывает inherited в последнюю очередь. Можно посмотреть куда-нибудь в корень... TPersistent, TComponent, TCollection...
Надо признать, там же масса примеров и обратного.
ИМХО, сперва почистить то, что знаешь (свое), а потом удалять самое себя более безопасный подход. Требовать же, корректно УбитьСебя, а потом убрать мусор... Подход истинного аристократа. ИМХО.
Пользуясь этой логикой, еще можно потребовать сначала создавать свои объекты, а потом уже вызывать создатель предка.

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


 
Германн ©   (2009-05-30 01:44) [23]


> Юрий Зотов ©   (29.05.09 18:28) [20]

+1
А по сабжу. Мне никогда не пришло на ум заменить Free на FreeAndNil.


 
Eraser ©   (2009-05-30 02:47) [24]

FreeAndNil помогает избежать багов (точнее более оперативно их находить) при повторном использовании переменных, что само по себе не лучший стиль программирования.


 
Юрий Зотов ©   (2009-05-30 19:36) [25]

> Нат ©   (30.05.09 01:34) [22]

> Требовать же, корректно УбитьСебя, а потом убрать мусор...

Хмм... а разве Вы не в курсе, что деструктор никаких "себя" вовсе не убивает?

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

Собственно, то же самое относится и к конструкторам, да и вообще, к любым перекрытым методом. Когда вызывать inherited, да и нужно ли его вообще вызывать - это решает исключительно программист. А всякие там "законы определяются исключительно грамматикой языка и средствами библиотеки времени выполнения. Других законов попросту не существует, все остальное - рекомендации, корпоративные стандарты, правила хорошего тона и т.п."

(c) Игорь Шевченко.

:o)


 
Юрий Зотов ©   (2009-05-30 19:46) [26]

> По сабжу

От повсеместной замены Free на FreeAndNil, конечно, вряд ли станет хуже (правда, нужно иметь в виду потенциальный подводный камень, о котором здесь уже говорилось и на который мы с Andryk"ом когда-то реально напоролись).

Но если человек пишет код с головой, то и лучше от такой замены тоже не станет.

А если человек пишет код без головы, то и замена ему не поможет.


 
oldman ©   (2009-05-30 19:47) [27]


> Ega23 ©   (29.05.09 12:58) [2]
> Знаешь, у меня вообще нигде FreeandNil нету. Вообще нигде.
>  И ничего.


Поддерживаю всеми руками...


 
Нат ©   (2009-05-31 02:21) [28]


> деструктор никаких "себя" вовсе не убивает

Вернее сказать, не всякий объект нуждается в уничтожении.
"Себя" состоит из двух частей - унаследованная и добавленная.
Добавленную (если надо) уничтожаем сами.
Унаследованную (если надо) поручаем предку.
Здесь правильно говориться, мол "надо знать предков".
Однако, при любом знании, бывает и проруха.
В общем случае, правильнее и безопаснее вызывать метод предка. ИМХО.
Там где надо, будет подметено, там где не надо - не будет.
Если, конечно, нет желания, уничтожая объект, какие-то части оставить для дальнейшего...
constructor TObject.Create;
begin
end;
destructor TObject.Destroy;
begin
end;
procedure TObject.Free;
begin
 if Self <> nil then
   Destroy;
end;


 
Anatoly Podgoretsky ©   (2009-05-31 09:59) [29]

> oldman  (30.05.2009 19:47:27)  [27]

И у меня нет ни одного и никогда не было в нем нужды, хотя бы из-за потери типизации, в результате чего теряем проверку на стадии компиляции.
Эта процедура была придумана для ленивых или хуже.


 
Юрий Зотов ©   (2009-05-31 13:59) [30]

По сути, название процедуры неточно. Правильнее было бы назвать ее NilAndFree.


 
Нат ©   (2009-05-31 13:59) [31]

Каким образом обNILивание приводит к потере проверок?


 
Anatoly Podgoretsky ©   (2009-05-31 14:17) [32]

> Нат  (31.05.2009 13:59:31)  [31]

Таким, что параметр процедуры нетипизированый указатель.


 
Дмитрий Белькевич   (2009-05-31 15:25) [33]

>А вот если где-то хранится ссылка ...

И он разрушится...


 
Дмитрий Белькевич   (2009-05-31 15:55) [34]

>вообще, при разработке класса-потомка знать особенности класса-предка даже не желательно, а обязательно

Вообще, зачем тогда вообще нужна инкапсуляция? ИИХО, один из её плюсов - то, что потомок не должен заморачиваться о том, что делает предок у себя внутри. И это знание не только не нужно, но и вредно. Это, конечно, если предок грамотно разработан, и не даст потомку себя покалечить.

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

Free, кстати, тоже как бы процедура, и self в неё передаётся, так Free как бы еще и метод...

>А если наоборот - значит, он должен написать наоборот.

У меня так вообще кое-где условные вызовы предковых методов бывают ;) Правда, не в конструкторах/деструкторах.

>А если человек пишет код без головы, то и замена ему не поможет.

То есть вы (я так предполагаю, что вы пишете код с головой) пишете код вообще без ошибок? И с доступом к разрушенным объектам уже наццать лет не сталкивались? Это хорошо, конечно, если так. К сожалению, не у всех получается.
Я у себя как раз откопал одно место, где идёт такое обращение. И это место (страшно подумать) уже не менялось 4-5 лет... Если не больше.
Правил чужой код, в нём было условное разрушение объекта (не заметил), и через несколько строчек - мой доступ к нему.

>Таким, что параметр процедуры нетипизированый указатель.

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


 
@!!ex ©   (2009-05-31 16:19) [35]

> [34] Дмитрий Белькевич   (31.05.09 15:55)
> Free, кстати, тоже как бы процедура, и self в неё передаётся,
> так Free как бы еще и метод...

речь шла о ЛИШНЕМ вызове.
Как бы FreeAndNil - процедру и она вызывает Free.


 
Mystic ©   (2009-05-31 16:31) [36]

> И с доступом к разрушенным объектам уже наццать лет не сталкивались?

Бывает, но редко. И там, где сталкивался, то FreeAndNil не помог бы... Потому как обычно это происходит, когда на один объект указывает две (и более) ссылок. По одной он освободился, по другой используется...


 
Нат ©   (2009-05-31 17:38) [37]

Процедура-функция... одинаково лишний вызов.
Большая проблема - другие ссылки на удаленный объект.
Если ручками удаляем, значит, про этот указатель знаем и так.
Для уверенности обнилить его можно тут же.
Напрямую, без лишних вызовов, передачи нетипизированых аргументов...
Особой пользы от F&N...


 
@!!ex ©   (2009-05-31 17:46) [38]

> [37] Нат ©   (31.05.09 17:38)
> Процедура-функция... одинаково лишний вызов.

У меня видимо плохо со счетом:
Object.Free() - один вызов.

FreeAndNil(Object) - один вызов
Object.Free() - второй вызов.


 
Palladin ©   (2009-05-31 18:02) [39]

Object:=Nil третье присвоение )

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


 
Anatoly Podgoretsky ©   (2009-05-31 18:03) [40]

Лозунн - долой строгую типизацию.


 
Anatoly Podgoretsky ©   (2009-05-31 18:07) [41]


> Palladin ©   (31.05.09 18:02) [39]

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


 
Юрий Зотов ©   (2009-05-31 19:31) [42]

> пишете код вообще без ошибок?
Без технических ошибок кодинга - практически.

> И с доступом к разрушенным объектам уже наццать лет не сталкивались?
Практически да.

PS
Как и с утечками памяти, неосвобожденными ресурсами и т.п.

PPS
И ничего удивительного в этом нет. Никто же не удивляется тому, что профессиональные музыканты практически не ошибаются в нотах? Все понимают, что ноты для них - это всего лишь азбука. Азы профессии.

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


 
Petr V. Abramov ©   (2009-05-31 23:00) [43]


> Юрий Зотов ©   (31.05.09 19:31) [42]


> Никто же не удивляется тому, что профессиональные музыканты
> практически не ошибаются в нотах?

"а если сунуть четвертак, то он сыграет и не так" :)


 
Дмитрий Белькевич   (2009-06-01 00:37) [44]

>Практически да.

И в команде работаете? И все такой код пишут? И чужой код всегда нормально удаётся исправлять? Можно только позавидовать...

>И ничего удивительного в этом нет.

> Типа напишем мы FreeAndNil, ну и ладно, что не проследил за использованием, все равно выскочит AV гдето по адресу около нулевого и там поймем... вместо того, что бы сразу приучать с малых лет себя не делать плохо, учат надеятся дядю FreeAndNil.

Поэтому я и предлагаю. Продвинуться дальше. И в тестовых целях менять Free на FreeAndNil. Уже прямо в памяти, без исправления сырцов.

p.s. У меня, кстати, на обниленных указателях на объекты кое-где логика строится, тоже не комильфо?


 
Германн ©   (2009-06-01 01:37) [45]


> > пишете код вообще без ошибок?
> Без технических ошибок кодинга - практически.
>

+1
Это на автомате.
Очепятки возможны. Но все компиляторы позволяют их излечивать/исправлять "на лету".


 
Нат ©   (2009-06-01 01:50) [46]

Лишний вызов, это значит, что нужные действия мы переносим совсем в другое место, в другую процедуру. И ее вызов тоже требует ресурсов и дополнительного исполняемого кода.
Object.Free; Object:=nil; //вызов одного метода, одно присвоение
//Либо
procedure FreeAndNil(var Obj); //вызов процедуры, передача аргумента
var
 Temp: TObject; //выделение переменной
begin
 Temp := TObject(Obj);  //приведение к типу, присвоение
 Pointer(Obj) := nil; //получение указателя, присвоение
 Temp.Free; //вызов метода
end; //возврат из процедуры


 
oxffff ©   (2009-06-01 10:09) [47]


> Германн ©   (01.06.09 01:37) [45]
>
> > > пишете код вообще без ошибок?
> > Без технических ошибок кодинга - практически.
> >
>
> +1
> Это на автомате.


Вы сказочник. :)


 
@!!ex ©   (2009-06-01 11:11) [48]

> [47] oxffff ©   (01.06.09 10:09)
> Вы сказочник. :)

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


 
oxffff ©   (2009-06-01 11:37) [49]


> @!!ex ©   (01.06.09 11:11) [48]


Исчо один сказочник. :)


 
Дмитрий Белькевич   (2009-06-01 12:16) [50]

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

Случайно обратил внимание, кстати, на Indy. Во многих местах именно FreeAndNil.


 
oxffff ©   (2009-06-01 12:47) [51]


> Дмитрий Белькевич   (01.06.09 12:16) [50]


Не ошибается тот, кто ничего нового не делает.


 
Игорь Шевченко ©   (2009-06-01 13:15) [52]

oxffff ©   (01.06.09 12:47) [51]

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

Кроме всего прочего я не так часто код набираю - я его стараюсь генерировать


 
jack128_   (2009-06-01 14:11) [53]


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

между "практически не ошибаются" и "не ошибаются" есть принципиальная разница.

Лично я стараюсь никогда не закладыватся на свой или не свой проф. навык.  И ассерты ставлю, и ReportOnMemoryLeak для более раннего обнаружения своих собственных ошибок. В том числе и FreeAndNil(FMyObjField) в деструкторе классов, как в примере выше.


 
Дмитрий Белькевич   (2009-06-01 14:18) [54]


> Кроме всего прочего я не так часто код набираю - я его стараюсь
> генерировать


И что-то сложнее "Hello World" получается? ;)


 
Дмитрий Белькевич   (2009-06-01 14:23) [55]

Хорошо, конечно, когда можно модели кода полностью собрать, и по ним готовый код сделать...

У нас, обычно, на момент старта написания программы, в лучшем случае, известно 20-30% её финальной функциональности. Поэтому почти всё - методом проб и ошибок.
И от нас мало зависит. Как бы проще сказать... Среда выполнения сильно нестационарная. Треть кода исследовательского - заранее неизвестно что получится, и получится ли вообще. Готовых рассчетных алгоритмов нет почти ни для чего, либо они недоступны, или запредельно дороги.

Ну а если бы задача заранее на 100% была описана, тогда, конечно - рисуй себе модель и генери код... Эхххх.... Жизнь малиной показалась бы ;)


 
Дмитрий Белькевич   (2009-06-01 14:27) [56]

Не говоря о том, с чем приходится сторонним работать... Куча оборудования, горы ошибок и нестандартного поведения. Почти от всех нет никакой вразумительной документации... В самих конторах - производителях оборудования (конкретно с Сименсом так было, был особенно тяжелый случай) бывает софт писали уже несколько лет назад и уже давно всех поувольняли. А те, кто работают, разбираться не могут и не будут... И так везде... Эххх... Генераторы кода - это сказка...


 
Игорь Шевченко ©   (2009-06-01 14:50) [57]

Дмитрий Белькевич   (01.06.09 14:18) [54]


> И что-то сложнее "Hello World" получается? ;)


Безусловно: HelloWorld1, HelloWordl2, HellowWorld3...


 
Дмитрий Белькевич   (2009-06-01 15:27) [58]


> Безусловно: HelloWorld1, HelloWordl2, HellowWorld3...


Шучу, конечно, не принимайте близко к сердцу ;)


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

Дмитрий Белькевич   (01.06.09 15:27) [58]

Да ни боже мой.
Просто у меня идиосинкразия к методу copy/paste, а код более или менее одинаковый приходится писать. Потому пусть лучше за меня его компьютер пишет - он железный :)


 
Дмитрий Белькевич   (2009-06-01 15:39) [60]


> Просто у меня идиосинкразия к методу copy/paste, а код более
> или менее одинаковый приходится писать.


Ну это да, копи/паст - это абсолютное зло...


 
oxffff ©   (2009-06-01 15:49) [61]


> Игорь Шевченко ©   (01.06.09 13:15) [52]
> oxffff ©   (01.06.09 12:47) [51]
>
> Боюсь, ты попал в сказочную страну - у меня тоже нет упомянутых
> ошибок ("технических ошибок кодинга").


Если вы каждый день имеете дело с одним и тем же, то было бы странно допускать ошибки. Для остальных случаях вы просто лукавите.
Вы подтверждаете мои слова в своем посте [59].


 
Игорь Шевченко ©   (2009-06-01 16:36) [62]

oxffff ©   (01.06.09 15:49) [61]

Может тебя забанить ?


 
oxffff ©   (2009-06-01 16:49) [63]


> Игорь Шевченко ©   (01.06.09 16:36) [62]


А за что?


 
oxffff ©   (2009-06-01 17:02) [64]


> Игорь Шевченко ©   (01.06.09 16:36) [62]


То есть вы будете продолжать настаивать, что для сложной системы,
где одни объекты связаны с другими, причем эти отношения могут быть как отношения владения, так и использования. Причем связи могут циклическими. Причем в эту схему могут вмешиваться внешние компоненты(не вы их автор) и устанавливать эти связи произвольно.
Вы напишите первую версию без багов?
Возмите VCL в ней до сих пор есть ошибки, возьмите языки программирования Delphi в нем есть ошибки.
Неужели вы считате себя более профессиональными чем авторы delphi и VCL?

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


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

> oxffff ©   (01.06.09 15:49) [61]

> Если вы каждый день имеете дело с одним и тем же

А что, у Вас каждый день новая Delphi с новым языком?

Если нет, то Вы не понимаете, о чем здесь идет речь.

Для остальных случаях вы просто лукавите.
(с) oxffff


 
oxffff ©   (2009-06-01 17:15) [66]


> Юрий Зотов ©   (01.06.09 17:03) [65]


Приветствую Вас, Юрий.
Я честно не понял в чем ко мне .....


 
Игорь Шевченко ©   (2009-06-01 17:26) [67]

oxffff ©   (01.06.09 17:02) [64]

Прочитай пост [42] внимательно, чтобы понять, о каких ошибках тебе говорят. Не надо вкладывать свой смысл в чужие слова и на основании этого вложенного своего смысла устраивать флейм.


 
Юрий Зотов ©   (2009-06-01 17:27) [68]

> oxffff ©   (01.06.09 17:15) [66]

Речь идет о технических ошибках кодинга. Например, забыть освободить память. Не отследить обращение к уже уничтоженному объекту. Не проинициализировать переменную. И т.п.

И какие бы Вы суперновые задачи ни решали, хоть ежедневно по десятку, Вы все равно пишете тот же самый код, на том же самом языке, с использованием той же самой библиотеки. Все те же GetMem/FreeMem, try/finally/except, Create/Free и т.п.

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

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

Это все равно, что певец, который не попадает в ноты.


 
AndreyV ©   (2009-06-01 17:34) [69]

> [57] Игорь Шевченко ©   (01.06.09 14:50)
> Дмитрий Белькевич   (01.06.09 14:18) [54]
> > И что-то сложнее "Hello World" получается? ;)
>
> Безусловно: HelloWorld1, HelloWordl2, HellowWorld3...

Гы. Только стишок запостил.;)
http://delphimaster.net/view/15-1237489213/
сообщение [185]


 
Дмитрий Белькевич   (2009-06-01 17:44) [70]

>Это все равно, что певец, который не попадает в ноты.

Увы, бывает... То, что вы слышите на CD (или на чем слушаете...) - это результат многонедельно отполированных записей. Концерты же, скажем так, неидеальны.


 
clickmaker ©   (2009-06-01 17:47) [71]

> Это все равно, что певец, который не попадает в ноты

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


 
Дмитрий Белькевич   (2009-06-01 17:47) [72]


> Концерты же, скажем так, неидеальны.


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

Программисткие же косяки обычно видны сразу.


 
Дмитрий Белькевич   (2009-06-01 17:48) [73]


> а вот, например, водитель автобуса, который постоянно забывает
> закрыть дверь, отъзжая от остановки - тут сравнение более
> уместное -)


Ему проще... Ему горит лямпочка - закрой... Вот автор тоже предлагает такую лямпочку добавить...


 
Дмитрий Белькевич   (2009-06-01 17:51) [74]


> это еще можно чем-то компенсировать...


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


 
clickmaker ©   (2009-06-01 17:56) [75]

> Слышали, кстати, как сейчас голоса вокодерами в попсе фильтруют

да я даже не про это.
Например, если певец поет что называется "с душой" плюс интересно обыгрывает свое выступление, ему можно простить полтона вправо, полтона влево.
А вот бывает поет ноль в ноль по нотам, но не цепляет...


 
AndreyV ©   (2009-06-01 17:59) [76]

> [74] Дмитрий Белькевич   (01.06.09 17:51)
> Слышали, кстати, как сейчас голоса вокодерами в попсе фильтруют
> (вероятно, хитро накладывая несущий тон), от чего меня просто
> коробит? А знакомого просто выворачивает...

Недавно постил сообщение [181] в
http://delphimaster.net/view/15-1237489213/
Девушка без вокодера так делает, если ты об этом. Оффтоп впрочем.


 
Ганя   (2009-06-01 23:31) [77]

Ну тут все верно - насчет технических ошибок кодинга.
Однако приведенная выше ситуация - по коду, приведенному в посте 7, и вероятная ошибка - обращение к разрушенному объекту за счет неверного представления о последовательности вызовов в предке - по моему мнению за рамки технических ошибок выходит.
Профессионал избегает технических ошибок на автоматизме, а в данном случае требуется анализ кода - возможно чужого, и ни о каком автоматизме речи быть не может.
У меня, по крайней мере, ошибки такого плана время от времени бывают (в то время, как технических ошибок также практически не бывает уже очень давно).
А вот уже после того, как выясняется, что лучше поставить разрушение приватного члена после inherited Destroy, можно с чистой совестью заменять FreeAndNil на Free

Так что про каждого овоща, который хорош в в свое время и место - все верно)


 
asails   (2009-06-02 15:49) [78]


> Юрий Зотов ©   (01.06.09 17:27) [68]

> Речь идет о технических ошибках кодинга.


Ага, мне тут как-то надо было всего-то диалоговое окно модально показать и убить... Причем юнит формы уже давно кем-то написан был. Вызываю так:
with TSuperPuperForm.Create(nil) do
try
 ShowModal;
finally
 Free;
end;


Казалось, чего уж проще?... Ан нет! Вылетает ексэпшн. Полез в код, и аж побледнел! Там примерно такое (сокращеный вариант ессно):
type
 TSuperPuperForm = class(TForm)
   procedure FormShow(Sender: TObject);
 end;

var
 SuperPuperForm: TSuperPuperForm;

implementation

{$R *.dfm}

procedure TSuperPuperForm.FormShow(Sender: TObject);
begin
 SuperPuperForm.Color := CL_MAINCOLOR;
end;


Причем я посмотрел, как оно до меня вызывалось и не падало, и узрел вот что:
SuperPuperForm := TSuperPuperForm.Create(nil);
 try
   SuperPuperForm.ShowModal;
 finally
   FreeAndNil(SuperPuperForm);
 end;


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


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


> with TSuperPuperForm.Create(nil) do
> try
>  ShowModal;
> finally
>  Free;
> end;


Я тебе Access Violation устрою мигом в такой конструкции - поставлю у формы Action := caFree на OnClose и AV тебе гарантирован.

Кстати, у ряда форм, от которых после показа не нужны никакие данные, такой OnClose мной установлен в предке :)


 
Юрий Зотов ©   (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]


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


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


 
Юрий Зотов ©   (2009-06-03 11:32) [121]

> Игорь Шевченко ©   (03.06.09 10:56) [120]

С того, что [19]. Надо ведь быть последовательным в своих высказываниях, не так ли?


 
Игорь Шевченко ©   (2009-06-03 12:08) [122]

Юрий Зотов ©   (03.06.09 11:32) [121]

А я, собственно, вполне последователен. [19] относится к деструктору, спорный фрагмент - к событию формы. Почувствуйте разницу


 
Юрий Зотов ©   (2009-06-03 12:26) [123]

> Игорь Шевченко ©   (03.06.09 12:08) [122]

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

Почувствуйте разницу.


 
Игорь Шевченко ©   (2009-06-03 12:46) [124]

Юрий Зотов ©   (03.06.09 12:26) [123]

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

Есть предложение завершить дискуссию.


 
Юрий Зотов ©   (2009-06-03 13:39) [125]

> Игорь Шевченко ©   (03.06.09 12:46) [124]

То есть, нет никакого смысла закрывать криворукому программисту возможность нарушить работу программы. В таком случае надо быть последовательным: все члены всех классов помещаем в public, все методы делаем виртуальными, все объявления выносим в interface - пущай себе резвится.

Предложение принимается.


 
Игорь Шевченко ©   (2009-06-03 13:40) [126]


> В таком случае надо быть последовательным: все члены всех
> классов помещаем в public, все методы делаем виртуальными,
>  все объявления выносим в interface - пущай себе резвится.
>


Дурное дело нехитрое


 
Дмитрий Белькевич   (2009-06-04 12:00) [127]

Итак... Очередной баг с помощью FreeAndNil откопал. Что характерно, с локально созданным и разрушенным объектом. Рассказываю.

Использую компоненты TBX. Для их редактирования использую модуль TBXEdit.

Вызываю его так:


TBXSetUpEditForm([TBXToolbar1, TBXToolbar3], [], [TBXItem126], fRegistryKey, 0, True, True, False, False, {nil,}
 PngImageList1);
ToolbarEditForm := TToolbarEditForm.Create(Self);
try
 ToolbarEditForm.ShowModal;
finally
 FreeAndNil(ToolbarEditForm);
end;


После изменения на FreeAndNil появилось AV при закрытии формы. Смотрим почему.

ToolbarEditForm - это глобальная переменная юнита TBXEdit:

var
ToolbarEditForm: TToolbarEditForm;

В юните есть такой код:


procedure DisableEdits;
begin
with ToolbarEditForm do
begin
 eCaption.Enabled := false;
 ......
 //Checkbox1.Enabled := false;
end;
end;


Этот код вызывается после разрушения формы. Как я понял, какое-то событие остаётся необработанным и вызывает этот код.

Таким образом мы видим:

1. Преимущество подхода тотальной (хотя бы временной) замены Free на FreeAndNil.
2. Неверно спроектированный код.
3. Недостатки использования сторонних компонент (хотя я их использую везде, где только могу).
4. Недостатки глобальных переменных.


 
Игорь Шевченко ©   (2009-06-04 12:28) [128]

Дмитрий Белькевич   (04.06.09 12:00) [127]


> 1. Преимущество подхода тотальной (хотя бы временной) замены
> Free на FreeAndNil.


Как средство поиска ошибок - любые средства хороши. В том числе и MemProof, BoundsChecker, FastMM с включенной опцией контроля утечек.


> 2. Неверно спроектированный код.


Дальше можно не рассказывать.


> 4. Недостатки глобальных переменных.


Дай дураку член стеклянный, он и руки порежет и член разобьет


 
Дмитрий Белькевич   (2009-06-04 13:49) [129]


> Как средство поиска ошибок - любые средства хороши. В том
> числе и MemProof, BoundsChecker, FastMM с включенной опцией
> контроля утечек.


Больше инструментов - не меньше. FastMM сам постоянно использую. Иногда и FullDebugMode включаю в нём. Иногда такое вылазит %)


 
Нат ©   (2009-06-04 19:27) [130]

Для глобальных и других долгоживущих переменных обНИЛивание полезно взять за правило
Оbj.Free; Obj:=nil;
Иначе проблематично применить
if not Assigned(Obj) then
          obj:=TObj.Create()



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

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

Наверх





Память: 0.89 MB
Время: 0.01 c
15-1243542627
Юрий
2009-05-29 00:30
2009.08.02
С днем рождения ! 29 мая 2009 пятница


15-1243586875
Дмитрий Белькевич
2009-05-29 12:47
2009.08.02
FreeAndNil против Free. Интересная концепция.


2-1242554718
jonin
2009-05-17 14:05
2009.08.02
Domain_name_IP_Traffic


11-1204559200
MiniQ9
2008-03-03 18:46
2009.08.02
FreePascal - Linux - KOL, как подружить?


15-1243695477
zdm
2009-05-30 18:57
2009.08.02
Windows 7 Delphi 2009 ошибка assertion failure





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
Английский Французский Немецкий Итальянский Португальский Русский Испанский