Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2005.12.25;
Скачать: CL | DM;

Вниз

Примеры кода, достойные орехов.   Найти похожие ветки 

 
jack128 ©   (2005-11-29 16:47) [40]

Суслик ©   (29.11.05 16:43) [39]
Ну в общем то да. И такое было  
var
 p: pointer;
begin
 ...
 try
   f := TObject(P) is TSomeObject;
 except
   f := False;
 end;
 if f then
   ...
end;

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


 
Суслик ©   (2005-11-29 16:54) [41]

2[40]

Да как сказать нулевая.

Пример.

type
  i = interface
     procedure SomeMethod();
  end;

  c = class(..., i) // подсчет ссылок отключен!
     procedure SomeMethod();
  end;

var
  o: c;
begin
  o := c.create();
  (c as i).SomeMethod.
  o.free();
end; // тут может быть очень суровый av

А все потому, что дельфи вызывает _release у неизвестно чего.

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


 
Игорь Шевченко ©   (2005-11-29 16:54) [42]

Владислав ©   (29.11.05 16:42) [38]

"Важной частью пропагандируемого мною стиля программирования является
разложение сложных процедур на небольшие методы. Если делать это неправильно,
то придется изрядно помучиться, выясняя, что же делают эти маленькие методы.
Избежать таких мучений помогает назначение методам хороших имен. Методам
следует давать имена, раскрывающие их назначение. Хороший способ для этого -
представить себе, каким должен быть комментарий к методу, и преобразовать
этот комментарий в имя метода.
Жизнь такова, что удачное имя может не сразу придти в голову. В подобной
ситуации может возникнуть соблазн бросить это занятие - в конце концов,
не в имени счастье. Это вас соблазняет бес, не слушайте его. Если вы видите,
что у метода плохое имя, обязательно измените его. Помните, что ваш код
в первую очередь предназначен человеку, а только потом - компьютеру.
Человеку нужны хорошие имена. Вспомните, сколько времени вы потратили,
пытаясь что-то сделать, и насколько проще было бы, окажись у пары методов
более удачные имена. Создание хороших имен - это мастерство, требующее
практики; совершенствование этого мастерства - ключ к превращению
в действительно искусного программиста.
То же справедливо и в отношении других элементов сигнатуры метода.
Если переупорядочивание параметров проясняет суть - выполните его."

(с) Мартин Фаулер


 
Суслик ©   (2005-11-29 16:55) [43]

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


 
jack128 ©   (2005-11-29 16:56) [44]

Суслик ©   (29.11.05 16:54) [41]
Помниться разовор на эту тему уже был ;) Раз не используешь подсчет ссылок, то все огрехи на тебе, а не на борланде ;)


 
Суслик ©   (2005-11-29 16:58) [45]

дело не к том, кто виноват.
а в том, что нельзя вызывать метод у неизветно чего :)
я только это утверждаю


 
Alkid ©   (2005-11-29 17:02) [46]

Типа реплика из аудитории, не дыша внимающей беседе: а это вообще правильно, что наследник от TObject приводится к Pointer`у? Вот уж сколько лет я программирую, но таких перлов делать не доводилось.
Так что этот спор, имхо, из разряда "как сделать из полной фигни что-то нормальное". Может не стоит изначально фигню писать?


 
Джо ©   (2005-11-29 17:04) [47]

[46] Alkid ©   (29.11.05 17:02)
>  а это вообще правильно, что наследник от TObject приводится
> к Pointer`у?

Вполне нормально, имхо. А вот наоборот - уже можно и огрести.


 
Ega23 ©   (2005-11-29 17:07) [48]


> Типа реплика из аудитории, не дыша внимающей беседе: а это
> вообще правильно, что наследник от TObject приводится к
> Pointer`у?


В TList все элемены к Pointer"у приводятся... И не только наследники TObject...  :о)


 
Суслик ©   (2005-11-29 17:08) [49]

Ну огрести это слишком.
Взять тот же TList.
Почему бы в него не засунуть TObject?


 
Alkid ©   (2005-11-29 17:09) [50]


> Вполне нормально, имхо. А вот наоборот - уже можно и огрести.

Нет, то, что операция приведения Pointer(TObject) легальна со всех точек зрения, кроме здравого смысла, я согласен. Но именно с точки зрения здравого смысла мы загоняем себя в яму из которой выбираемся проявляя чудеса изобретательности (очень уж это в нашем менталитете сильно ;) )
Можно не Pointer а тот самый TObject сделать? Или сделать интерфейс и передавать через него. Вообще, если нет возможности передать значение типа TObject, то скоее всего мы имеем дело с каким-то смешанным кодом, где два дельфёвых куска программы взаимодейстуют через ж... т.е. недельфёвый кусок кода, который дельфёвые типы не разумеет. В этом случае надо использовать интерфейсы, для того они и сделаны.


 
Ega23 ©   (2005-11-29 17:11) [51]


> Можно не Pointer а тот самый TObject сделать?


А для этого существует не TList, а TObjectList...   :о)


 
Владислав ©   (2005-11-29 17:14) [52]


> Игорь Шевченко ©   (29.11.05 16:54) [42]


Игорь, а к чему здесь это было процитировано?


 
Alkid ©   (2005-11-29 17:16) [53]


> А для этого существует не TList, а TObjectList...   :о)

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


 
Гость1   (2005-11-29 17:18) [54]


> А для этого существует не TList, а TObjectList...   :о)

TThreadList - ? Есть объектные аналоги?


> Alkid ©   (29.11.05 17:09) [50]

А как быть с TTreeView? Конкретно, с TTreeNode.Data кода нужно в узлы объекты помещать?


 
Джо ©   (2005-11-29 17:18) [55]


>  [53] Alkid ©   (29.11.05 17:16)
> [50] Alkid ©   (29.11.05 17:09)

Согласен.


 
Ega23 ©   (2005-11-29 17:21) [56]


> И вообще, хорошая практика - порождение специализированных
> классов для объектов определённого типа (наследников от
> определённого класса). При этом используемый класс списка
> (тот же TObjectList) лучше инкапсулировать, что бы кто-нибудь
> не положил в него что-то лишнее, не приводимое к нашему
> классу. Тогда все эти проблемы типа "блин, вот Pointer,
> а как узнать, что в нём лежит?!" отпадают сразу.


А кто с этим спорит?


 
Игорь Шевченко ©   (2005-11-29 17:22) [57]

Владислав ©   (29.11.05 17:14) [52]


> Игорь, а к чему здесь это было процитировано?


А к тому, что метод называется Chars а делает вовсе не то.


 
Владислав ©   (2005-11-29 17:29) [58]


> Игорь Шевченко ©   (29.11.05 17:22) [57]
>
> А к тому, что метод называется Chars а делает вовсе не то.
>


Хе-хе :)
Видать я к таким выкидонам уже привык на новой работе, что меня это уже не напрягает.

Я когда переписывал код с вызовом этой функции (у нас новая версия продукта пишется), новый код у меня не сразу скомпилировался. Так я просто пошел к реализации функции (это уже обыденное дело). Заменил вызов Chars() на StringOfChar().

Мартин Фаулер может спать спокойно?.. :)


 
Alkid ©   (2005-11-29 17:29) [59]


> > А для этого существует не TList, а TObjectList...   :о)
>
> TThreadList - ? Есть объектные аналоги?
  А самому сделать слабо? Я, например, написал однажды потокозащищённый класс для объектов, и для строк и для ещё чего-то. Уже три года пользуюсь и не парюсь.

> > Alkid ©   (29.11.05 17:09) [50]
>
> А как быть с TTreeView? Конкретно, с TTreeNode.Data кода
> нужно в узлы объекты помещать?

 Вот тут идея хромает, ибо нет возможности самому делать наследников от TTreeNode пихать в них произвольные данные и пихать их в дерево. Это явный недостаток класса TTreeNodes. Приходится извращаться. Как правило я просто инкапсулировал TTreeView целиком, что бы предотвратить несанкционированный доступ к его данных как к Pointer`ам. Это гарантировало мне, что в Data лежит что-то вполне конкретное и я могу приводить его обратно к нужному типу без проблем. А вообще я когда только можно пользуюсь собственными классами для обслуживания древесных структур в памяти.


 
Alkid ©   (2005-11-29 17:33) [60]

Кстати о TTreeView, там есть protected функция CreateNode, выступающая в роли фабрики класса узлов дерева. Функцию можно перегрузить, что бы она штамповала не TTreeNode, а наследников от него, в которые можно определить любые поля по вкусу. Так что не всё так пасмурно на древесном фронте :)


 
Гость1   (2005-11-29 17:43) [61]


> Вот тут идея хромает, ибо нет возможности самому делать
> наследников от TTreeNode пихать в них произвольные данные
> и пихать их в дерево.

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

Я знаю, что все надо переписывать в соответствии с правилами, но тут ключевое слово "лень", которое маскируется словом "целесообразность". :)

Про потокозащищенный объектный список я спросил лишь из-за того, что может я плохо хелп читал и он реализован. :)


 
Alkid ©   (2005-11-29 17:58) [62]


> Не, тут все путем,
> есть OnCreateNodeClass, где в зависимости от условий указываешь
> класс создаваемого узла.
  Ну вообще всё круто :)
>
> Я знаю, что все надо переписывать в соответствии с правилами,
>  но тут ключевое слово "лень", которое маскируется словом
> "целесообразность". :)
   Это дело понятное :)
>
> Про потокозащищенный объектный список я спросил лишь из-
> за того, что может я плохо хелп читал и он реализован. :
> )

 Нет, в хелпе и правда такого зверя нет. Я и про TThreadList не слышал раньше, если честно. А потокозащищённые контейнеры делал сам, вооружившись TCriticalSection :-)


 
Суслик ©   (2005-11-29 21:06) [63]

Up.

Очень хотелось бы услышать комментарии digitman"а по поводу его кода [33] и моих возражений по поводу того, что нельзя вызывать методы у неизвестно чего.

Данный интерес вызван тем, что вполне возможно, что я ошибаюсь и можно вызывать.
Чудеса бывают. Например, я видел код, в котором, есть self.free в середине метода, но написано все корректно - после free нет обращений, к полям self - только к стековым переменным (т.е. локальным) или глобальным. В итоге все работает корректно.

Может бють и здесь есть какая-то неучтенная мною хитрость.


 
имя   (2005-11-29 21:39) [64]

Удалено модератором


 
jack128 ©   (2005-11-29 22:00) [65]

Борис Березовский   (29.11.05 21:39) [64]
PostQuitMessage(Msg.wParam);

Зачем это??  А так, нормальная функция, если писать на API. Хотя можно и лудше если вместо Sleep(StepMsgUpdate); написать
if MsgWaitForMultipleObjects(0, nil^, False, I - GetTickCount, QS_ALLINPUT) = WAIT_TIMEOUT then
     Exit;


 
jack128 ©   (2005-11-29 22:16) [66]

Суслик ©   (29.11.05 21:06) [63]
Например, я видел код, в котором, есть self.free в середине метода, но написано все корректно - после free нет обращений, к полям self - только к стековым переменным (т.е. локальным) или глобальным. В итоге все работает корректно.

А это абсолютно корректный(по крайней мере с технической точки зрения) подход. Насчет кода Дигитмена - да, он опасен. Он ничем не отличается от такого:
var
 P: TProcedure;
begin
 P := TProcedure(Pointer(Integer(Random(MaxInt))));
 P;
end;
Проблема в том, что мы вообще неизвестно какой код вызываем..


 
vuk ©   (2005-11-29 22:27) [67]

to jack128 ©   (29.11.05 22:16) [66]:
>Насчет кода Дигитмена - да, он опасен.
В принципе да, но там нам остается неизвестным окружение, в котором код работает. Если в obj гарантировано будет интерфейсная ссылка, то все нормально.


 
jack128 ©   (2005-11-29 22:29) [68]

vuk ©   (29.11.05 22:27) [67]
Если в obj гарантировано будет интерфейсная ссылка,

То всю эту функцию можно переписать как
Result := Assigned(P)  ;)


 
vuk ©   (2005-11-29 22:32) [69]

to jack128 ©   (29.11.05 22:29) [68]:
>То всю эту функцию можно переписать как
Не совсем. Если внимательно посмотрите, то там ветвление и проверяются два разных интерфейса.


 
jack128 ©   (2005-11-29 22:36) [70]

Да, не обратил внимание, сорри.


 
Uncle Archi ©   (2005-11-29 23:08) [71]

jack128 ©   (29.11.05 22:16) [66]
Этот код всего навсего дает Accsess Voliation в одном и том же адресе, или, если поставить RandomIze, то в разных.. )))


 
evvcom ©   (2005-11-30 08:31) [72]


> Alkid ©   (29.11.05 16:36) [37]
>
> > Вот если можно заставить грузиться по одному адресу, то
>
> > действительно как средство защиты можно рассматривать.
>  Тогда
> > всё понятно.
> > Только я первый раз про такое слышу.
> > Собственно, поэтому и спросил...
>
> В принципе каждый модуль (в том числе и .exe) имеет заданный
> в PE файле базовый адрес. И при расположении сегментов модуля
> этот базовый адрес используется как точка отсчёта. Можно
> ли этот факт использовать для защиты - ХЗ.

Базовый адрес имеется и загрузчик туда и загрузит, если место еще не занято. Но использовать этот факт нельзя, потому как нет никакой гарантии, что эти адреса к моменту загрузки действительно будут свободны и загрузчик не переместит вследствие этого модуль в другие адреса.


> Как правило я просто инкапсулировал TTreeView целиком, что
> бы предотвратить несанкционированный доступ к его данных
> как к Pointer`ам. Это гарантировало мне, что в Data лежит
> что-то вполне конкретное

Да нифига не гарантирует. Ну есть у тебя TMyTreeNode.Data: TObject, а я такой "извращенец" беру и делаю:
var
 MyIntVar: Integer;
begin
 MyTreeNode.Data := TObject(@MyIntVar);
 // Да хоть и так:
 MyTreeNode.Data := TObject(Pointer(MyIntVar));

И все! Все специально писанное инкапсулирование, "гарантирующее" абсолютную корректность коту под хвост. Просто программист, работающий с указателями и преобразованиями типов, должен четко себе представлять, что он делает, и подобные, потенциально опасные участки кода подробно комментировать (для потомков). Мое имхо.


 
Alkid ©   (2005-11-30 10:32) [73]


> Да нифига не гарантирует. Ну есть у тебя TMyTreeNode.Data:
>  TObject, а я такой "извращенец" беру и делаю:
> var
>  MyIntVar: Integer;
> begin
>  MyTreeNode.Data := TObject(@MyIntVar);
>  // Да хоть и так:
>  MyTreeNode.Data := TObject(Pointer(MyIntVar));
>
> И все! Все специально писанное инкапсулирование, "гарантирующее"
> абсолютную корректность коту под хвост. Просто программист,
>  работающий с указателями и преобразованиями типов, должен
> четко себе представлять, что он делает, и подобные, потенциально
> опасные участки кода подробно комментировать (для потомков).
>  Мое имхо.

Ну, если программист хочет разложить себе на будущее грабелек, что бы по ним потом увлекательно погулять, то он может делать такие вещи. От извращенцев и просто некомпетентных программистов ни один код не застрахован (хотя уже в Java & .NET такие вещи не пройдут).

Здесь просто мы на самом деле затронули более общую проблему:
Программист должен делать свои классы такими, что бы количество потенциальных граблей, на которые можно наступить неправильным применением его кода, было минимальным и грабли эти были наиболее очевидны. По этому речь идёт не о том, что я написал гениальный класс, с которым и полный дебил напишет неглючащую программу. Речь идёт о том, что я написал более безопасный класс, так как там вещи называются своими именами: TObject называется TObject`ом, а не Pointer`ом. А значит на будущее создал себе меньше граблей  :-)


 
TUser ©   (2005-11-30 11:10) [74]

Я уже приводил пример. Как поддерживается - не в курсе.
http://monkey.belozersky.msu.su/~evgeniy/tokens.c

ЗЫ. А что "такого" в первом и третьем примере из топика?


 
Alkid ©   (2005-11-30 11:21) [75]


> http://monkey.belozersky.msu.su/~evgeniy/tokens.c

ЗачОт! Код сколь гениальный, столь и нехороший в плане поддержки этого дела. Единственное оправдание такому коду - это если бы он был автоматически сгенерирован :)

Вообще в бытность C++ программистом (сейчас я по долгу службы переполз на Delphi, а "для души" программирую на C# в C#Builder`e) я тоже иногда вот так изголялся и писал извращённый код. В этом смысле C++ богат возможностями для экономии битов и тактов. Но потом пришёл к выводу, что начиная с программ уже среднего размера читаемость кода и его логическая прозрачность гораздо более важны, чем лихость такая программирования.


 
Владислав ©   (2005-11-30 11:22) [76]

Э-э-э... В первом и третьем посте?


 
jack128 ©   (2005-11-30 11:26) [77]

Владислав ©   (30.11.05 11:22) [76]
третьем посте

не посте, а примере. Тот что Коля М привел. Я уже сказал, что это код Борланда.


 
iZEN ©   (2005-11-30 14:59) [78]

Вот ещё:

import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
public class GaugeMidlet extends MIDlet implements CommandListener {
   private Display display;
   private Command CMD_EXIT = new Command("EXIT", Command.EXIT, 1);
   private Command CMD_OK = new Command("OK", Command.OK, 1);
   private Form inputForm;
   private TextField nameText;
   private Form gaugeForm;
   private Gauge searchGauge;
   public GaugeMidlet() {
       display = Display.getDisplay(this);
       inputForm = new Form("Параметры");
       nameText = new TextField("Фамилия", "", 20, TextField.ANY);
       inputForm.append(nameText);
       inputForm.addCommand(CMD_EXIT);
       inputForm.addCommand(CMD_OK);
       inputForm.setCommandListener(this);
   }
   public void startApp() {
       display.setCurrent(inputForm);
   }
   public void pauseApp() {}
   public void destroyApp(boolean unconditional) {}
   public void commandAction(Command command, Displayable screen) {
       if (command == CMD_EXIT) {
           destroyApp(false);
           notifyDestroyed();
       }
       if (command == CMD_OK) {
           gaugeForm = new Form("ищет...");
           searchGauge = new Gauge("", false, 20, 1);
           gaugeForm.append(searchGauge);
           gaugeForm.addCommand(CMD_EXIT);
           gaugeForm.setCommandListener(this);
           display.setCurrent(gaugeForm);
           searchGauge.setValue(0);
           for (int i = 0; i < 10000000; i++) {}
           searchGauge.setValue(10);
           for (int i = 0; i < 10000000; i++) {}
           searchGauge.setValue(20);
       }
   }
}

В общем, я офигеваю от такого качества знаний кодеров. Что же там в J2ME-играх творится, одним им известно...


 
Суслик ©   (2005-11-30 15:10) [79]

2iZEN

окромя задержки через for вроде все приемлемо
наверное детали какие-то я упустил...


 
iZEN ©   (2005-11-30 20:51) [80]


> Суслик ©   (30.11.05 15:10) [79]

А если подумать хорошенько. То код выполняться будет не так.
searchGauge.setValue(...); не асинхронный, а это значит, что в обработчике commandAction мы получим не то что конкретный зависон на циклах, но и необновление компонента searchGauge.
По окончании работы commandAction, конечно же, searchGauge будет иметь значение 20.
Здесь по-хорошему нужна отдельная нить (что я и реализовал в нескольких вариантах, включая разработку отдельного небольшого/независимого от J2ME фреймворка. На будущее...).



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

Текущий архив: 2005.12.25;
Скачать: CL | DM;

Наверх




Память: 0.66 MB
Время: 0.039 c
2-1134075049
replace
2005-12-08 23:50
2005.12.25
замена букв


14-1133767491
Кабан
2005-12-05 10:24
2005.12.25
Спектр


14-1132315308
DiamondShark
2005-11-18 15:01
2005.12.25
Ненавижу ЮИ


2-1134038542
kyn66
2005-12-08 13:42
2005.12.25
Данные из таблицы показать в ComboBox


2-1133874781
Daria
2005-12-06 16:13
2005.12.25
Добавить запить в БД