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

Вниз

Free()   Найти похожие ветки 

 
Loginov Dmitry ©   (2007-02-18 09:15) [0]

Насколько идеологически/практически правильно/неправильно подменять метод Free(), реализованный у TObject своим собственным методом Free()? В своем классе, наследуемом от TObject, я выполнил такую вот подмену, и теперь мой Free() со 100% гарантией будет вызывать метод Destroy только для реально "живых" объектов, иначе сгенерирует исключение. Теперь сомнения мучают, нет ли тут каких-нибудь неучтенных граблей?


 
Loginov Dmitry ©   (2007-02-18 09:22) [1]

Реализация практически таже, что и у TObject


 procedure TMatrix.Free;
 begin
   if Self = nil then Exit;
   if not MatrixRefIsValid(Self) then
     DoMatrixError(matSRefIsNotMatrix, "procedure TMatrix.Free");
   Destroy;  
 end;


 
Ketmar ©   (2007-02-18 09:59) [2]

а чем не приглянулся нормальный сборщик мусора?


 
Аноним   (2007-02-18 10:09) [3]

Предположим, ты поместил свой  объект TMatrix в ObjectList
и предполагаешь, что при разрушении листа твой объект разрушится.
Так и будет, только твой метод  Free при этом никто не вызовет
(точно так же случится, если твой объект будет разрушаться кем то ,кто не знает про класс TMatrix)
Неправильно короче.
Переопределяй деструктор, или BeforeDestruction - то есть виртуальные методы, а не статические


 
Loginov Dmitry ©   (2007-02-18 10:09) [4]

> а чем не приглянулся нормальный сборщик мусора?


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


 
Loginov Dmitry ©   (2007-02-18 10:18) [5]

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


Это-та да. Но на такие жертвы пойти можно ради повышения качества.


> Переопределяй деструктор, или BeforeDestruction - то есть
> виртуальные методы, а не статические


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


 
Аноним   (2007-02-18 10:29) [6]


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


В случае повторного деструктора статичность метода  нас не спасет,потому что, судя по if not MatrixRefIsValid(Self) then
все равно предстоит обращение к полям.

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


 
Loginov Dmitry ©   (2007-02-18 10:44) [7]

> В случае повторного деструктора статичность метода  нас
> не спасет,потому что, судя по if not MatrixRefIsValid(Self)
> then
> все равно предстоит обращение к полям.


Повторюсь, что MatrixRefIsValid(Self) гарантированно возвращает True для "живых" объектов. Для всех прочих объектов (и "необъектов") эта функция возвращает False. Гарантия - 100%. Почему - это уже вопрос по реализации данной функции.


 
Ketmar ©   (2007-02-18 11:05) [8]

> Loginov Dmitry ©   (18.02.07 10:09) [4]
а тем, что подобные "защиты" делают для предотвращения "double destruction" и "stale pointers". с GC такой ерунды просто не бывает.


 
Loginov Dmitry ©   (2007-02-18 11:18) [9]

Приведи пример использования нормального сборщика мусора для предотвращения "double destruction" и "stale pointers". Может тогда до меня дойдет, что ты имеешь ввиду...


 
Ketmar ©   (2007-02-18 11:23) [10]

> Loginov Dmitry ©   (18.02.07 11:18) [9]
читай статьи про GC. или подумай, как может появиться первое/второе в системе, где
а) объекты никто руками не уничтожает, и, следовательно,
б) все указатели на управляемые объекты всегда валидны.


 
Юрий Зотов ©   (2007-02-18 11:33) [11]

> Loginov Dmitry

> ради повышения качества

Я бы не сказал, что это повышение качества. Скорее понижение. Потому что во всех сотнях (если не тысячах) мест, где Free вызывается из VCL, будет вызван "родной", а не Ваш Free. В итоге желаемого Вы все равно не добъетесь, а результатом будет только путаница, ничего более.

Так что - какое же это "повышение качества"? Это понижение.


 
Loginov Dmitry ©   (2007-02-18 11:37) [12]

Так я и не понял, на решение какой проблемы был направлен пост [2]?


 
Ketmar ©   (2007-02-18 11:40) [13]

> Loginov Dmitry ©   (18.02.07 11:37) [12]
мётлы обещали скоро подвезти. записываю в очередь.


 
Loginov Dmitry ©   (2007-02-18 11:49) [14]

> [11] Юрий Зотов ©   (18.02.07 11:33)

> Я бы не сказал, что это повышение качества. Скорее понижение.
> Потому что во всех сотнях (если не тысячах) мест, где Free
> вызывается из VCL, будет вызван "родной", а не Ваш Free


Я бы очень сильно удивился, еслиб вдруг где-нибудь из VCL был вызван мой Free :))


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


Мне достаточно такого результата, чтобы для объекта AObject: TMatrix был был вызван мой метод Free(). Чтобы система адекватно реагировала на такие ситуации:

AObject := TByteMatrix.Create;
AObject.Free;
AObject.Free;

И при втором вызове Free() обращение к виртуальному методу Destroy не произошло.
Хорошо, если кроме путаницы (хотя какая тут еще путаница может быть) ничего плохого не произойдет. Для меня главное, чтобы мой метод Free() из-за такой вот подмены ничего не "сломал".


> Так что - какое же это "повышение качества"? Это понижение.


Это Ваше личное мнение. Спорить в Вами я не могу.


 
Loginov Dmitry ©   (2007-02-18 11:50) [15]

> мётлы обещали скоро подвезти. записываю в очередь.


И давно ты в этом бизнесе работаешь?


 
Юрий Зотов ©   (2007-02-18 11:56) [16]

> Loginov Dmitry ©   (18.02.07 11:49) [14]

AObject := TByteMatrix.Create;
TObject(AObject).Free; // Это автоматический вызов из VCL
AObject.Free; // А это Ваш вызов.

И получаем все те же грабли.

Поэтому: "В итоге желаемого Вы все равно не добъетесь, а результатом будет только путаница".


 
Loginov Dmitry ©   (2007-02-18 12:02) [17]

> AObject := TByteMatrix.Create;
> TObject(AObject).Free; // Это автоматический вызов из VCL
> AObject.Free; // А это Ваш вызов.
>
> И получаем все те же грабли.


С чего вы взяли, что получим те же грабли. Грабли будут только при таком вызове:

AObject := TByteMatrix.Create;
TObject(AObject).Free; // Это автоматический вызов из VCL
TObject(AObject).Free; // Это автоматический вызов из VCL


 
Аноним   (2007-02-18 12:05) [18]


> Я бы очень сильно удивился, еслиб вдруг где-нибудь из VCL
> был вызван мой Free :))


Удивишься, удивишься.
Дело в том, что системы имеют такое свойство - жить некоей жизнью и меняться. На это должна ставиться закладка с самого начала.\
Сейчас VCL не вызовет, а потом программа будет меняться (например даже не тобой, а другим программистом) и этот вызов появится.
А другой программист должен будет знать, что "нельзя так делать", хотя при стандартном поведении классов так делать можно.

Собственно, ты е спрашиваешь про идеологию? А не про то, чтобы "сейчас заработало".
Есть такой паттерн проектирования - называется "детонатор".
Хочешь его - на здоровье, никто тут с тобой спорить не будет


 
Loginov Dmitry ©   (2007-02-18 12:17) [19]

> Сейчас VCL не вызовет, а потом программа будет меняться
> (например даже не тобой, а другим программистом) и этот
> вызов появится.


Даже не другим программистом, а десятками и сотнями программистов. Проект очень ответственный, иначе бы я не завел данной ветки, и не стал бы выделываться в подменой метода Free(). Это я делаю с целью облегчения работы с системой, с целью своевременного обнаружения ситуаций повторного уничтожения.


> А другой программист должен будет знать, что "нельзя так
> делать", хотя при стандартном поведении классов так делать
> можно.


Почему же так делать нельзя. Можно. Хочешь - вызывай TObject(AObject).Free; Хочешь - вызывай AObject.Free; Я не считаю, что при вызове AObject.Free дополнительная проверка на существование объекта кому-то может помешать.


 
Аноним   (2007-02-18 12:31) [20]


> Loginov Dmitry ©


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

Мне кается, ты берешь на себя не свои функции. Посмотри в VCL - там разве есть что-то подобное?

Если совсем приперло - назови метод по другому
типа
FreeCheckValid


 
Юрий Зотов ©   (2007-02-18 14:02) [21]

> Loginov Dmitry ©   (18.02.07 12:02) [17]
> С чего вы взяли, что получим те же грабли.

Из Вашего кода. После вызова стандартного Free параметр Self в Вашем Free будет битой ссылкой (но не nil). И получим те же грабли.


 
Юрий Зотов ©   (2007-02-18 14:31) [22]

> Loginov Dmitry ©

Собственно, что зря спорить? Напишите десяток строк и все увидите сами.

Делаю потомка Вашего объекта:

type
 TMyMatrix = class(TByteMatrix)
 private
   FSomeField: integer;
 public
   destructor Destroy; override;
 end;

destructor TMyMatrix.Destroy;
begin
 FSomeField  = 0;
 inherited;
end;

Теперь проверяем, как сработает Ваш Free после вызова стандартного:

procedure TForm1.Button1Click(Sender: TObject);
var
 AObject: TMyMatrix;
begin
 AObject := TMyMatrix.Create;
 TObject(AObject).Free; // VCL будет вызывать Free именно так
 AObject.Free; // А это вызов Вашего Free.
end;

И в Вашем Free получим AV - либо при вызове MatrixRefIsValid (если там есть обращения к полям объекта), либо при вызове деструктора (потому что в деструкторе TMyMatrix обращение к полям точно есть).

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

Например, вставят Ваш объект (или его потомка) в TObjectList, а потом, согласно Вашей же рекомендации не придадут значения лишнему Free в своем коде и получат все то же самое AV.

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


 
jack128 ©   (2007-02-18 14:50) [23]

Удалено модератором
Примечание: Словарный запас сокращай. Накажу


 
jack128 ©   (2007-02-18 14:52) [24]

jack128 ©   (18.02.07 14:50) [23]
А, блин.  Насчет BeforeDestruction я поторопился :-)


 
Суслик ©   (2007-02-18 15:11) [25]

2автор.
ужасный метод free.
причем ничего "со 100% гарантией" не гарантирует.

сам подумай.


 
Суслик ©   (2007-02-18 15:15) [26]

для повышения качества *очень* советую использовать FastMM в полной версии (качается в www.sourceforge.net).

В нем есть опция - проверять вызов виртуальных методов у уничтоженных объектов. Как известно деструктор виртуален. Так вот ФастММ радостно это ловит. Причем говорит:
1. Стек вызовов когда объект был создан.
2. Стек вызовов когда уничтожен.
3. Стек вызовов при вызове вирт. метода уничтоженного объекта.

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


 
Leonid Troyanovsky ©   (2007-02-18 16:09) [27]


> Loginov Dmitry ©   (18.02.07 09:15)  

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

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

Подобные гарантии возможны, например, для механизма Notification,
т.е., среди компонентов.

Все остальное - от лукавого.

Кста, if not Assigned(..) then Destroy - делает обычный Free, т.е.,
нет смысла уточнять его здесь.
Проблема лишь в том, что ссылок на единственный объект
может быть более одной.

--
Regards, LVT.


 
Anatoly Podgoretsky ©   (2007-02-18 16:55) [28]

> Loginov Dmitry  (18.02.2007 11:50:15)  [15]

Ты не поверишь, это крупнейший распространитель метл.


 
Loginov Dmitry ©   (2007-02-20 08:07) [29]

> [20] Аноним   (18.02.07 12:31)
> Если совсем приперло - назови метод по другому
> типа
> FreeCheckValid


Придется сделать примерно также. Помещу собстенный метод Free() внутри блока условной компиляции. Добавлю статичный метод FreeMatrix, в который помещу текст [1]. Получится примерно следующее:


{$ifdef UseExtendedFree}
procedure Free;
begin
  FreeMatrix;
end;
{$ifdef UseExtendedFree}



> [21] Юрий Зотов ©   (18.02.07 14:02)
> > Loginov Dmitry ©   (18.02.07 12:02) [17]
> > С чего вы взяли, что получим те же грабли.
>
> Из Вашего кода. После вызова стандартного Free параметр
> Self в Вашем Free будет битой ссылкой (но не nil). И получим
> те же грабли.


Выдачу AV с указанием причины ошибки и места ее возникновения Вы называете граблями?


> И в Вашем Free получим AV - либо при вызове MatrixRefIsValid
> (если там есть обращения к полям объекта), либо при вызове
> деструктора (потому что в деструкторе TMyMatrix обращение
> к полям точно есть).


Вот код функции MatrixRefIsValid():

function MatrixRefIsValid(AMatrix: TMatrix): Boolean;
begin

 if AMatrix = nil then
 begin
   Result := False;
   Exit;
 end;

 Result := True;
 try
   if not IsEqualGUID(AMatrix.FLifeGUID, LifeMatrixGuid)
     {or not (TObject(AMatrix) is TMatrix)}
     {К сожалению, мы не всегда можем использовать операцию проверки IS.
      Допустим, если есть EXE и DLL, откомпилированные с Matrix32 без
      использования пакетов, то операция IS сработает некорректно. Именно
      по этой причине эту операцию в данном модуле вы нигде не найдете.}
   then
     Result := False;
 except // Обращение AMatrix.FLifeGUID может привести к исключению
   Result := False;
 end;
end;


Обращение к полю объекта находится в защищенном блоке.

А при вызове деструктора получение AV наиболее вероятно из-за обнуления указателя на VMT, а не из-за обращения к полям уничтоженного объекта. Даже если AV не возникнет, то проверка ссылки в BeforeDestruction - неплохой выход.


> [26] Суслик ©   (18.02.07 15:15)
> для повышения качества *очень* советую использовать FastMM
> в полной версии (качается в www.sourceforge.net).


Советовать мне FastMM - это лишнее. Можно и без него прекрасно обойтись.


> Для того, чтобы быть уверенным, что имеешь дело с живым
> объектом, необходима уверенность, что удерживаемая в руках
> ссылка валидна,
> и, по крайней мере, была вовремя обнулена при разрушении
> объекта.
>
> Подобные гарантии возможны, например, для механизма Notification,
> т.е., среди компонентов.


Данный механизм я давно и успешно использую.


 
Ketmar ©   (2007-02-20 09:33) [30]

> Loginov Dmitry ©   (20.02.07 08:07) [29]
> Выдачу AV с указанием причины ошибки и места ее возникновения
> Вы называете граблями?

а что, выдача AV -- это теперь "нормальное поведение"? хоть трижды место ошибки укажи -- всё равно грабли.


 
Loginov Dmitry ©   (2007-02-20 10:09) [31]

> а что, выдача AV -- это теперь "нормальное поведение"? хоть
> трижды место ошибки укажи -- всё равно грабли.


Я имел ввиду не AV, а просто генерацию собственного исключения.


 
evvcom ©   (2007-02-20 10:28) [32]

> [31] Loginov Dmitry ©   (20.02.07 10:09)
> просто генерацию собственного исключения

Да какая разница? Если ссылку на объект хранит другой объект, настрой нотификацию, как уже было сказано в [27]. Тогда никаких повторных разрушений не будет. (Ну это, правда, как настроишь :)


 
Ketmar ©   (2007-02-20 10:34) [33]

> Loginov Dmitry ©   (20.02.07 10:09) [31]
"фраза не моя, я её просто напечатал".


 
vecna ©   (2007-02-20 10:37) [34]

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


 
Аноним   (2007-02-20 10:53) [35]


> Loginov Dmitry ©


> Вот код функции MatrixRefIsValid():


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


 
Loginov Dmitry ©   (2007-02-20 11:18) [36]

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


Использовать такой глобальный список я не хочу по 3-м причинам:
1 - не хочу иметь проблем при использовании многопоточности
2 - при создании большого числа объектов работа со списком начнет тормозить
3 - при компиляции модуля без пакетов в EXE и в DLL списки будут у каждого свои, и функция будет работать неверно.


 
evvcom ©   (2007-02-20 11:24) [37]

> [36] Loginov Dmitry ©   (20.02.07 11:18)

1. детский лепет.
2. большого - это миллион? Куда столько?
3. а не надо так делать. Даже в твоем случае дублирование кода класса уже не правильно.

Ты подумай все ж над тем, что в твоей консерватории что-то не так.


 
Loginov Dmitry ©   (2007-02-20 12:00) [38]

> 2. большого - это миллион? Куда столько?


А может и миллион. Мало ли...


> 3. а не надо так делать. Даже в твоем случае дублирование
> кода класса уже не правильно.


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


> Ты подумай все ж над тем, что в твоей консерватории что-
> то не так.


Все так.


 
ЮЮ ©   (2007-02-20 12:05) [39]


> Loginov Dmitry ©   (20.02.07 12:00) [38]


Похоже, сомнения, мучавшие при написании subj-а, совсем прошли :)


 
evvcom ©   (2007-02-20 12:11) [40]

> [38] Loginov Dmitry ©   (20.02.07 12:00)
> Все так.

Хозяин - барин. Тогда зачем ты здесь?


 
Loginov Dmitry ©   (2007-02-20 12:11) [41]

> Похоже, сомнения, мучавшие при написании subj-а, совсем
> прошли :)


Да совсем прошли. Если 2/3 постов проигнорить, то получится, что все "благословили" мою задумку :))


 
ЮЮ ©   (2007-02-20 12:23) [42]


Если 2/3 постов проигнорить,

то останется 1/3 твоих постов. Ибо ни в одном, кроме твоих, благословения не наблюдал :)


 
Аноним   (2007-02-20 12:53) [43]


> Использовать такой глобальный список я не хочу по 3-м причинам:
>
> 1 - не хочу иметь проблем при использовании многопоточности
> 2 - при создании большого числа объектов работа со списком
> начнет тормозить
> 3 - при компиляции модуля без пакетов в EXE и в DLL списки
> будут у каждого свои, и функция будет работать неверно.


1. Обходится тремя доп строками кода.
2. Не будет тормозить. Если их и правда миллион - сортировать список по абс. значению указателя - летать будет со свистом
а если не миллион а тысяца - то и без сортировки не заметишь тормозов - операция очень быстрая
3. Ты что - собираешься эти матрицы между exe и Dll передавать в виде указателей и без bwrtp ?
Если так, то удачи желать бесполезно, ее не будет


 
reonid ©   (2007-02-20 12:58) [44]

2Loginov Dmitry ©   (20.02.07 12:11)

Мне кажется, будет милосерднее по отношению к пользователям
твоей библиотеки дать им разбираться со своими ошибками, чем с твоими.
Лекарство может оказаться хуже болезни. ИМХО...


 
icWasya ©   (2007-02-20 12:59) [45]

А не лучше сделать так ?

procedure FreeAndNil(var M:TMatrix);overload;
var
 MM:TMatrix;
begin
 MM:=M;
 M:=Nil;
 if MM = nil then Exit;
 if  MatrixRefIsValid(MM) then Destroy;  
end;


 
Lamer@fools.ua ©   (2007-02-20 13:07) [46]

После [19], пожалуй, соглашусь с [13].


 
Loginov Dmitry ©   (2007-02-20 15:08) [47]

> [43] Аноним   (20.02.07 12:53)
>
> 1. Обходится тремя доп строками кода.
> 2. Не будет тормозить. Если их и правда миллион - сортировать
> список по абс. значению указателя - летать будет со свистом
> а если не миллион а тысяца - то и без сортировки не заметишь
> тормозов - операция очень быстрая


Для чего писать якобы 3 строки кода, если существующий механизм итак отлично работает? Он надежный, быстрый, с ним никаких проблем. Что такого особенного даст то, что я буду использовать глобальный список? Надежность? Нет (надежнее программа не станет)! Скорость? Врядли (если только тормоза внесет)! Только дополнительную работу и описанную проблему с DLL.


> 3. Ты что - собираешься эти матрицы между exe и Dll передавать
> в виде указателей и без bwrtp ?


А что тут такого? Подключил ShareMem (FastMM и т.п.) - и вперед. Главное, чтобы программа не глючила. А глобальный список будет таким стремлениям только мешать.

Кстати дай расшифровку буквосочетанию bwrtp...


> [44] reonid ©   (20.02.07 12:58)
>
> Мне кажется, будет милосерднее по отношению к пользователям
> твоей библиотеки дать им разбираться со своими ошибками, чем с твоими.


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

Как вы думаете, сколько времени должно уйти на поиск ошибки, подобной этой:


 procedure TForm1.Button1Click(Sender: TObject);
 var
   AList: TList;
 begin
   AList := TList.Create;
   AList.Free;
   AList.Free;
 end;


В 70% случаев повторный вызов AList.Free; никакого AV не выдает - все просто замечательно. Однако AV начинают появляться при работе программы в дальнейшем. Пользователь работает, работает - и бац - AV. Причем адрес в тексте ошибок может быть любым. С другой стороны после повторного вызова Free ошибка может и не возникнут. И так от запуска к запуску - то AV, то все нормально. Вот дела-то!
Потом: AV после повторного вызова Free() не всегда бывает шуточным. Эта ошибка может запросто парализовать дальнейшую работу всего приложения. Выловить такую ошибку - достаточно трудно (я-то привел простейший случай, когда 2 Free идут подряд друг за другом, в жизни обычно не так). Такие ошибки профессионалы не допускают. Новичек - запросто! Профессионал если даже и допустит подобную ошибку - в его арсенале куча отладочных средств и других возможностей. У новичка - напротив. С одной ошибкой может е...ться сутками.

Я же в рамках своего класса предлагаю очень простой выход из подобных крайне редких ситуаций. Меня же за это пинают все кто на что горазд. Однако никто так и не сумел однозначно сказать, почему это х..ня. Ссылаются на VCL, Notifycation, и бог знает на что еще. Некоторые даже начали учить искуству дворника (вероятно ищут себе замену).


> [46] Lamer@fools.ua ©   (20.02.07 13:07)
> После [19], пожалуй, соглашусь с [13].


Тоже ищете себе замену?


 
Сергей М. ©   (2007-02-20 15:30) [48]


> Loginov Dmitry ©   (20.02.07 15:08) [47]


> Как вы думаете, сколько времени должно уйти на поиск ошибки,
>  подобной этой


Сколько бы ни ушло, это не твоя ошибка, а ошибка разработчика, использующено твой класс.

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


 
Аноним   (2007-02-20 16:58) [49]


> Loginov Dmitry ©


> А что тут такого? Подключил ShareMem (FastMM и т.п.) - и
> вперед.


то есть программисту надо будет еще и как минимум помнить, что нельзя использовать IS (AS), а как максимум - что нужно обязательно собирать  хост и библиотеку с одинаковыми настройками выравнивания, и так далее?
а также забыть о языковой независимости, и о варианте "хост и библиотека собраны разными версиями D"
Это уже намного серьезнее, чем внесение путаницы в Free.

Я просто так делал, давно еще. И получил в результате те самые

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

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


> Кстати дай расшифровку буквосочетанию bwrtp...


Build with run time packages


 
Суслик ©   (2007-02-20 17:16) [50]

вот упрямый то :)
спорить с тобой бессмыслено.

очень советую распространять свою библиотеку в ТОЛЬКО в бинарниках - чтобы никто кода не видел ибо ни один программист пользовать библиотеку с таким кодом не будет ибо это вызывает сомнения в образовании автора библиотеки.

ЗЫ
вот эта функция function MatrixRefIsValid(AMatrix: TMatrix): Boolean еще вроде ничего - похожа на работоспособную ибо обращение к AMatrix.FLifeGUID ни к чему, кроме AV привести не может, т.к. FLifeGUID есть поле, а не метод.
т.е. не будет ни privileged instruction, ни порчи чужой памяти.


 
Ketmar ©   (2007-02-20 17:37) [51]

из очереди на метлу вычёркиваю. или сломает, или потеряет.


 
oldman ©   (2007-02-20 17:43) [52]


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


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


 
Loginov Dmitry ©   (2007-02-20 17:54) [53]

> очень советую распространять свою библиотеку в ТОЛЬКО в
> бинарниках - чтобы никто кода не видел ибо ни один программист
> пользовать библиотеку с таким кодом не будет ибо это вызывает
> сомнения в образовании автора библиотеки.


Сказать честно - зря вы так! Библиотека большая, спорного кода очень немного. Весь этот спорный код я привел здесь. Реакцию на этот код почувствовал на себе. Всю критику я учел и сделаю соответствующие изменения в библиотеке.

> вот эта функция function MatrixRefIsValid(AMatrix: TMatrix)
> : Boolean еще вроде ничего - похожа на работоспособную ибо
> обращение к AMatrix.FLifeGUID ни к чему, кроме AV привести
> не может


Безболезненный AV - наиболее "опасная" ситуация при обращении к полю FLifeGUID.
Даже этого AV практически никогда не возникает.


 
Суслик ©   (2007-02-20 17:59) [54]


>  [53] Loginov Dmitry ©   (20.02.07 17:54)


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

В любом языке есть некоторые precondition, а precondition на то они и precondition, что их фиг проверишь - "живость" объекта есть ответственность вызывающей стороны. Если вызывающая сторона испытывает сложности с отладкой - на это есть тот самый fastmm.


 
Суслик ©   (2007-02-20 18:04) [55]

Еще.

уж поверь, что информативность fastmm много выше, чем информативность предоставляемая твоим способом.

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

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

тот же fastmm тебе выведет подробный стек, где и когда был объект удален в предыдущий раз.


 
Loginov Dmitry ©   (2007-02-20 18:07) [56]

Я сейчас в большинстве проектов юзаю FastMM4. Вы правы - штука действительно офигительная. Забудешь один байт освободить, так и будет докапываться, пока все не исправишь :)


 
Суслик ©   (2007-02-20 18:13) [57]

Я очень рад за тебя, что ты это дело юзаешь.
Прьер переодически правит ее, и библиотека становится все более полезной.
Ты все равно ее не переплюнешь в части помощи пользователю, да и зачем это надо? Он очень граммотный программист, я с ним переодически переписываюсь - его уровень знания RTL много выше чем наш с тобой. Ты лучше ошибку в ней найди какую-нибудь :) В основном все правки - это именно баги, найденные в части сервисных функций данного манагера памяти.

Лучше рассчитывать на то, что твой пользователь не новичок, раз пользуется такой библиотекой как твоя :) (шутка, ну ты понял).


 
Lamer@fools.ua ©   (2007-02-20 18:24) [58]

>>Loginov Dmitry ©   (20.02.07 15:08) [47]

>Тоже ищете себе замену?
Не-е. Дело в том, что кроме меня ещё один ламер нужен. Только покруче.


 
Loginov Dmitry ©   (2007-02-20 18:32) [59]

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


Я давным-давно знаю про это и вполне четко понимаю. У меня проверка Self стоит и в деструкторе, так что, грубо говоря, в 50% случаев программа на эту проверку напорется даже при попытке уничтожения объекта с помощью "битой" ссилки, хранимой в TObjectList. Это не панацея. Для большего у меня возможностей нет.


> Ты все равно ее не переплюнешь в части помощи пользователю,
> да и зачем это надо? Он очень граммотный программист, я
> с ним переодически переписываюсь - его уровень знания RTL
> много выше чем наш с тобой. Ты лучше ошибку в ней найди
> какую-нибудь :) В основном все правки - это именно баги,
> найденные в части сервисных функций данного манагера памяти.


Я час читал это историю по исправлению баг (так и не дочитал). Наверное целая армия участвовала в этом процессе. Так что я согласен что это самый мощный манагер памяти :)


> Лучше рассчитывать на то, что твой пользователь не новичок,
> раз пользуется такой библиотекой как твоя :) (шутка, ну
> ты понял).


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


 
Суслик ©   (2007-02-20 18:41) [60]


> Я давным-давно знаю про это и вполне четко понимаю. У меня
> проверка Self стоит и в деструкторе, так что, грубо говоря,
> в 50% случаев программа на эту проверку напорется даже при
> попытке уничтожения объекта с помощью "битой" ссилки, хранимой
> в TObjectList. Это не панацея. Для большего у меня возможностей
> нет.

Э... как бы тебе сказать - ты здесь в корне не прав :)
деструктор метод виртуальный. Верно? К чему межет привести вызов виртуального метода у битой ссылки? Ладно уж к AV, намного хуже, что может вызываться вообще черт значет что. Со всеми вытекающими - порча чужих данных и все такое. После этого программа может потерять работоспособность как таковая.


> Я час читал это историю по исправлению баг (так и не дочитал).
> Наверное целая армия участвовала в этом процессе. Так что
> я согласен что это самый мощный манагер памяти :)

Нет, он один. Он единственный автор. А вот баги и идеи пишут многие. Из России в том числе несколько человек. Я тоже какой-то баг там находил - он в *некоторых случаях* неверно определял тип утекаемых данных если это была строка. Ты тоже можешь принять участие.


> Это очень сложная и ответственная задача (сколько библиотек
> кроме FastMM выполняют такие требования?)

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


 
Ketmar ©   (2007-02-20 18:44) [61]

хм. мрамрные шарики тоже не доверять.


 
Суслик ©   (2007-02-20 18:45) [62]

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

Ерунда какая-то. Т.е. ты делаешь лишнюю работу.


 
Loginov Dmitry ©   (2007-02-20 18:46) [63]

> Э... как бы тебе сказать - ты здесь в корне не прав :)
> деструктор метод виртуальный. Верно? К чему межет привести
> вызов виртуального метода у битой ссылки? Ладно уж к AV,
> намного хуже, что может вызываться вообще черт значет что.
> Со всеми вытекающими - порча чужих данных и все такое. После
> этого программа может потерять работоспособность как таковая.


Вы повторили то, что я описывал в [47] насчет AList.Free.


 
Суслик ©   (2007-02-20 18:49) [64]

А ты почитай [62] - там тоже мысль здравая.
Желаю успехов.


 
Суслик ©   (2007-02-20 18:51) [65]

2автор
в борландовом QC открыты репорты по перегрузке _initializeRecord и _finalizeRecord. Если они это сделают, то ты с полным правом можешь реализовывать на основе этого некое подобие сборщика мусора. Пока же - это мертвому припарки - если чесловек (твой пользователь) не соблюдает precondition, то ему не нужно писать на языке, на котором он пишет.


 
Ketmar ©   (2007-02-20 19:35) [66]

> Суслик ©   (20.02.07 18:51) [65]
оставь надежду... раньше Дима был адекватный. а теперь стал "нормальным".


 
Суслик ©   (2007-02-20 19:43) [67]


>  [66] Ketmar ©   (20.02.07 19:35)

Я тут неожиданно почуял высшую миссию нести истину людям :)


 
Loginov Dmitry ©   (2007-02-20 19:55) [68]

На компромисс я всеж-таки пошел:

добавил опцию условной компиляции UseExtendedFree для компиляции собственного метода Free()
добавил опцию условной компиляции UseLifeGuid. Если она отключена, то используется (в потокобезопасном режиме) список созданных объектов TList.

И чем не компромисс?


> Я тут неожиданно почуял высшую миссию нести истину людям :)


Там это все вспомнят и воздадут по заслугам, и вознесут... :))


 
evvcom ©   (2007-02-21 09:17) [69]

> [61] Ketmar ©   (20.02.07 18:44)
> хм. мрамрные шарики тоже не доверять

Да чего мраморные? Бери круче, титановые!


 
Аноним   (2007-02-21 09:41) [70]


> Loginov Dmitry ©


> добавил опцию условной компиляции


Ну и зря :-)
ИМХО, чем меньше дефайнов, тем лучше. Я лично ввожу их только в том случае, когда без них совсем никак. А ты на ровном месте аж две штуки породил. Если так пойдет дальше, в них потом сам черт ногу сломит.


 
Суслик ©   (2007-02-21 10:30) [71]


> Ну и зря :-)
> ИМХО, чем меньше дефайнов, тем лучше. Я лично ввожу их только
> в том случае, когда без них совсем никак. А ты на ровном
> месте аж две штуки породил. Если так пойдет дальше, в них
> потом сам черт ногу сломит.


сильно от задачи зависит.
самый жуткий модуль, который я видел это fastmm4.pas - безумное кол-во дефайнов.


 
Loginov Dmitry ©   (2007-02-21 12:57) [72]

> ИМХО, чем меньше дефайнов, тем лучше. Я лично ввожу их только
> в том случае, когда без них совсем никак. А ты на ровном
> месте аж две штуки породил. Если так пойдет дальше, в них
> потом сам черт ногу сломит.


А не сломит. Там комментарии есть. На русском :))


 
Loginov Dmitry ©   (2007-02-22 23:56) [73]

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

http://matrix.kladovka.net.ru/download.php?getfilename=uploads/heart/matrix32.zip

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


 
Юрий Зотов ©   (2007-02-23 10:26) [74]


procedure RaiseException(const AText: string);
begin
 raise Exception.Create(AText);
end;

function TMatrix.DimCols: Integer;
begin
 if DimensionCount > 0 then
   Result := DimensionCount - 1
 else begin
   RaiseException(matSDimensionError);
   Result := -1;
 end;
end;

Дмитрий, если честно, то мое личное ИМХО такое - я считаю, что выделенная строка свидетельствует, что квалификация программиста недостаточна для того, чтобы его коду можно было доверять даже на 90%. А без 99%-ной уверенности я чужой код не использую.


 
Юрий Зотов ©   (2007-02-23 11:19) [75]

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

type
 EMatrixError = class(EMathError);

procedure RaiseMatrixError(const AText: string);
begin
 raise EMatrixError.Create(AText)
end;

function TMatrix.DimCols: Integer;
begin
 if DimensionCount <= 0 then
   RaiseMatrixError(matSDimensionError);
 Result := DimensionCount - 1
end;

Вроде бы, то же самое? То же, да не совсем.

Во-первых, свой класс исключения (причем c правильным по смыслу наследованием) позволяет мне, как пользователю библиотеки, строить в моей программе гибкую обработку ошибок - и сам факт того, что автор об этом позаботился, уже говорит о том, что уровень его мышления перерос рамки прикладного программирования (for end-user) и созрел до уровня, необходимого для разработки инструментария. То есть, о достаточном опыте и квалификации.

Во-вторых, код полон и одновременно компактен (то есть, в нем есть все, что нужно и нет ни одной лишней буквы). ИМХО, такой четкий стиль тоже свидетельствует о том, что коду верить можно.


 
Суслик ©   (2007-02-23 11:47) [76]

2[75]
Со всем согласен, кроме пользы от наследования от EMathError.
Расскажи, если не сложно, пример практической пользы наследования от EMathError.

PS. Я лично всегда объявляю предка для исключения, который свойственнен текущей библиотеке или классу

Например

type
  TMatrix = class
     public type EException = class abstract(Exception);
     public type EWrongCoord = class sealed(EException);
     public procedure GetValue(const aRow, aCol: Integer): Integer;
     strict private function fValidCoord(const aRow, aCol: Integer): Boolean;
  end;  
...
procedure TMyClass.GetValue(const aRow, aCol: Integer): Integer;
begin
  if not fValidCoord(aRow, aCol) then
     raise EWrongCoord.Create(".....");
  ...
end;


 
Юрий Зотов ©   (2007-02-23 16:14) [77]

> Суслик ©   (23.02.07 11:47) [76]

> всегда объявляю предка для исключения, который свойственнен текущей
> библиотеке или классу

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

> пример практической пользы наследования от EMathError.

Насколько я понял, библиотека Matrix по сути своей - математическая. Значит, помимо ее собственных исключений при работе с ней могут возникать и другие математические исключения (переполнение, деление на ноль и т.п.) - и все они потомки EMathError. Поэтому, если EMatrixError тоже отнаследовать от EMathError, то юзер, не теряя возможности отлавливать конкретные исключения, получает еще и возможность отлова разом всех математических исключений (в том числе, и исключения самой библиотеки) c их единой обработкой (если в данном месте кода юзеру конкретизация не нужна):

...
except
 on E: EMathError do
   обработка
end;

Если же наследовать EMatrixError от общего Exception, то в данном примере обязательно пришлось бы писать повтор:

...
except
 on E: EMatrixError do
   обработка;
 on E: EMathError do
   та_же_ самая_обработка;
end;

А при наследовании от EMathError обязательность повтора исчезает. Можно делать и так, и так - что в данном месте требуется, то и делаем. И говорим "спасибо" автору, позаботившемуся о гибкости и удобстве использования своей библиотеки.
:о)


 
Anatoly Podgoretsky ©   (2007-02-23 17:55) [78]

> Loginov Dmitry  (22.02.2007 23:56:13)  [73]

Даже не надейся, слишком самоуверен.


 
Суслик ©   (2007-02-23 21:49) [79]


> Юрий Зотов ©   (23.02.07 16:14) [77]

нет в этом практической пользы.


 
Юрий Зотов ©   (2007-02-23 21:55) [80]

> Суслик ©   (23.02.07 21:49) [79]

Ой ли?
:o)


 
Суслик ©   (2007-02-23 22:41) [81]


> Юрий Зотов ©   (23.02.07 21:55) [80]
> > Суслик ©   (23.02.07 21:49) [79]
>
> Ой ли?
> :o)


Точно-точно.

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

Не мне тебе объяснять как исключения бывают сделаны в других языках :)
Речь о том, что EMathError - типичное runtime исключение (деление на ноль - что тебе даст его обработка? , если ты, конечно, не положился на обработку этого исключения в своем алгоритме, что не есть, скорее всего, хорошо).

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

Подведу итог вот чем - мат. ошибка - типичное runtime исключение - его обработка бессмыслена. Поэтому выгода того, что ты наследуешься не от Exception, а от EMathError не в том, что библиотека гибка, а в том, что ты за неимением инаструментария в языке сам начинаешь делить и исключения на runtime и обрабатываемые (не помню, как они в java называется). В этом выгода. ИМХО. Надеюсь понятно.


 
Loginov Dmitry ©   (2007-02-24 00:09) [82]

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


Каким образом выделенная строчка в данном случае о чем-то может свидетельстовать? Ну "мертвый" код. Ну не доглядел. Спасибо что заметили. Возможно и где-нибудь еще есть подобная оплошность. Исправлю.
Пути хода програмерской мысли неисповедимы :)

Вопросик, если можно: Существует ли в мире такой код (кроме конечно Вашего собственного), которому вы бы могли доверять на 99%. И еще: что для Вас важнее - идеально написанный код, либо надежное обеспечение заявленной функциональности?


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


А почему Вы считаете, что EMatrixError следует наследовать именно от EMathError? Может я чего-то не допонимаю, но каким образом наследование от EMathError позволит организовать гибкую обработку ошибок?

Еще: вместо Вашего варианта функции RaiseMatrixError() я разработал функцию DoMatrixError(). Она достаточно информативна, и кроме сообщения об ошибке показывает также дополнительную информацию: время ошибки, последовательность вызванных процедур, приведшая к возникновению ошибки. Не знаю как Вы, но я считаю такой подход очень удобным. Допустим есть вот такая функция:

 function TNumericMatrixClass.ValueOperation(const Matrix: TMatrix;
   Value: Extended; AFunc: TFloatOperation): TMatrix;
 var
   I: Integer;
 const
   SFuncName = "function TNumericMatrixClass.ValueOperation";
 begin
   if Self <> Matrix then
     Resize(Matrix.FDimensions);

   try

     for I := 0 to FElemCount - 1 do
       VecElem[I] := AFunc(Matrix.VecElem[I], Value);

   except
     on E: EMatrixError do DoMatrixError(E.Message, SFuncName);
     on E: Exception do DoError(E.Message, SFuncName);
   end;

   Result := Self;
 end;


При выполнении функции математической функции AFunc() может произойти в общем случае какая угодно ошибка (то же деление на ноль). Либо в ходе присвоения VecElem[I] := возникнет ошибка переполнения разрядной сетки. В итоге выполнится строка on E: Exception do DoError(E.Message, SFuncName);, которая сгенерирует исключение EMatrixError, и текст ошибки будет содержать подробнейший отчет: имя массива, класс массива, тип элементов массива, размеры массива, занимаемая память, время ошибки, последовательность вызванных процедур. На мой взгляд - весьма подробная информация для того, чтобы программист не тратил долгих часов на ее поиски. О делении на ноль программист, я считаю, должен думать заранее. Плюс к этому Matrix32 никого не обязывает использовать встроенные в него вычислительные функции. Если Ваш алгоритм подразумевает использование таких экстремальных операций, как деление на ноль, то оформите для этого собственную процедуру, если стандартная обработка ошибок Matrix32 Вас не устраивает.
Поскольку я считаю реализованный на данный момент в Matrix32 механизм обработки ошибок весьма удобным, и проверенным на практике (меня, как не только создателя, но еще и как пользователя Matrix32 данный подход устраивает на все 100, достойных альтернатив ему я придумать не могу), расставаться с ним только из-за того, что Вам зачем-то понадобилось иметь свой класс для каждой генерируемой ошибки, я не стану. Давайте вместе подумает, какой еще достойной альтернативой можно можно заменить существующий механизм обработки ошибок, где найти компромисс?


> Во-вторых, код полон и одновременно компактен (то есть,
> в нем есть все, что нужно и нет ни одной лишней буквы).


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


> Насколько я понял, библиотека Matrix по сути своей - математическая.
> Значит, помимо ее собственных исключений при работе с ней
> могут возникать и другие математические исключения (переполнение,
> деление на ноль и т.п.) - и все они потомки EMathError.
> Поэтому, если EMatrixError тоже отнаследовать от EMathError,
> то юзер, не теряя возможности отлавливать конкретные исключения,
> получает еще и возможность отлова разом всех математических
> исключений (в том числе, и исключения самой библиотеки)
> c их единой обработкой (если в данном месте кода юзеру конкретизация
> не нужна):


Интересно, а кому нужно для каждой ошибки анализировать возникшее исключение. Честно - мне ни разу не приходилось писать такой вот код:

try
  A := B / C;
except
  on EZeroDivide do..
  on EOverflow do..
  on EUnderflow do..
end;


Ну просто не возникает такой необходимости. Если в образовательных целях - то ладно, еще можно разок попробовать. Но вот где и зачем это использовать на практике - не понятно. Вероятно, задача - крайне специфическая. Если можно, дайте пример, где это необходимо (только не такие, как: on EZeroDivide do ShowMessage("Ой! Деление на ноль")).


 
Юрий Зотов ©   (2007-02-24 00:26) [83]

> Суслик ©   (23.02.07 22:41) [81]

> деление на ноль - что тебе даст его обработка?

В численных алгоритмах может дать ОЧЕНЬ многое. Уточнять нужно? Честно говоря, тратить время влом, поэтому лучше просто поверь - но если будешь настаивать, то приведу пример, когда обработка, например, деления на ноль позволяет довольно просто получить решение, которое без этой обработки было бы либо не получить совсем, либо гораздо сложнее.

> runtime исключение - его обработка бессмыслена

Дим, вдумайся (только правда - сделай паузу и спокойно ВДУМАЙСЯ) - это ведь бред. Деление исключений на run-time и обрабатываемые - бред. Во-первых, когда программа УЖЕ запущена и УЖЕ работает, ЛЮБОЕ исключение становится run-time, как ты его ни дели. Во-вторых, ЛЮБОЕ исключение, независимо от его источника, должно допускать ЛЮБУЮ свою обработку (от полного игнорирования до полного Halt) - иначе чего будет стоить программа, неподвластная даже программисту?

> в Java

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


 
Суслик ©   (2007-02-24 00:31) [84]


> Юрий Зотов ©   (24.02.07 00:26) [83]

Весь этот разговор настолько долог, что скорее подходит для личной беседы и споров :)


 
Суслик ©   (2007-02-24 00:36) [85]


> Юрий Зотов ©   (24.02.07 00:26) [83]

Все же несколько конкретизирую.
Все мое высказываение относилось к обоснованности наследования от EMathError. Более ничего.

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


 
Юрий Зотов ©   (2007-02-24 01:30) [86]

> Loginov Dmitry ©   (24.02.07 00:09) [82]

> Каким образом выделенная строчка в данном случае о чем-то может
> свидетельстовать?

Очень простым - ДЕЙСТВИТЕЛЬНО квалифицированный программист ТАКОГО не напишет НИКОГДА. Даже спьяну. Встроенный автопилот не пустит.

> Ну не доглядел.

Нет. Не "не доглядел", а "еще нет автопилота". См. п.1.

> Возможно и где-нибудь еще есть подобная оплошность.

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

> Существует ли в мире такой код (кроме конечно Вашего собственного),
> которому вы бы могли доверять на 99%.

Конечно. Это код тех пакетов, которые я использую, или использовал на предыдущих местах работы. Например, Rx, Dx, DC, FR, EhGrid, FC и другие. Я видел этот код, я понял КЕМ и КАК он написан - поэтому ЕМУ я действительно верю. Кстати, СВОЕМУ коду я верю меньше. Не потому, что программирую хуже или там лучше - не в этом даже дело. А уже потому, что объем тестирования этих пакетов существенно больше, чем у моего кода. Таковы реалии и о них нужно помнить.

> что для Вас важнее - идеально написанный код, либо надежное
> обеспечение заявленной функциональности?

Софистика. Потому что это одно и то же. ЗАЯВИТЬ можно что угодно, но вот НАДЕЖНО ОБЕСПЕЧИТЬ заявленное без ОТЛИЧНО написанного кода - это не получится. Осетрины второй свежести не бывает. И именно поэтому, когда в коде я вижу откровенные ляпы, то понимаю, что его писал человек с недостаточной квалификацией - соответственно, перестаю верить, что код ДЕЙСТВИТЕЛЬНО обеспечит заявленную функциональность. Как следствие, юзать такой код я не стану. Хватает и своих глюков, зачем еще чужие? Свои я хоть знаю, где править, а с чужими еще разбираться придется.

> каким образом наследование от EMathError позволит организовать гибкую
> обработку ошибок?

Так. Читаем ВНИМАТЕЛЬНО. И чужих слов не ИСКАЖАЕМ. Я говорил, что гибкую обработку ошибок позволяет реализовать СВОЕ исключение (которого у Вас нет). От чего бы оно ни порождалось. Еще я говорил, что будет лучше, если породить его от EMathError. Почему - см. [77].

> вместо Вашего варианта функции RaiseMatrixError()

Простите, ВАШЕГО. В ней я всего лишь заменил имя и класс исключения.

> я разработал функцию DoMatrixError(). Она достаточно информативна, и
> кроме сообщения об ошибке показывает также дополнительную
> информацию: время ошибки, последовательность вызванных процедур,

Это здорово. Безусловное достижение. Заслуживает инкремента мажора.
LOL.

> О делении на ноль программист, я считаю, должен думать заранее.

Да. Причем, не только о нем. Вы ведь программист?
:о)

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

В таких случаях Кейт рекомендует метлу. Я не столь категоричен, поэтому рекомендую больше практики.

> Посмотрите свои собственные исходные коды - мне что-то не верится, что
> в них нет ни одной лишней буквы

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

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

Вот именно. Кстати, и не для open-source - тоже, разницы нет. Именно этим я, в основном, и занимаюсь последние лет этак 8-10.

> мне ни разу не приходилось писать такой вот код:
> ...
> Ну просто не возникает такой необходимости.

ПОКА не приходилось ПОКА не возникало. Но разработчик ИНСТРУМЕНТАРИЯ просто ОБЯЗАН такие вещи предвидеть. Иначе - однозначно РАНО ему еще ИНСТРУМЕНТАРИЙ писать, прикладник он еще по сути своей.

> Если можно, дайте пример

См. [83]. "Честно говоря, тратить время влом, поэтому лучше просто поверь - но если будешь настаивать, то приведу пример, когда обработка, например, деления на ноль позволяет довольно просто получить решение, которое без этой обработки было бы либо не получить совсем, либо гораздо сложнее".

Надеюсь, Вы уже знаете, что я ничего никогда не говорю просто так. Поэтому - если пример нужен, я его приведу, но лучше просто поверьте на слово. Поскольку пример этот будет связан с численными алгоритмами, чтобы он был понятен, многое придется разжевывать и потребуется совсем не час времени. А мне его жаль. Моего СЛОВА - недостаточно?


 
Юрий Зотов ©   (2007-02-24 01:45) [87]

> Суслик ©   (24.02.07 00:31) [84]

Дим, ты еще никогда не был так прав, как в [84]
:о)

> Суслик ©   (24.02.07 00:36) [85]

Пример навскидку. Представь, что ты ищешь корень уравнения в области, охватывающей начало координат. Решение, как обычно, идет методом последовательных приближений (неважно, каким именно). В каком-то выражении для вычисления нового (суженного) интервала локализации корня используется деление на текущий X. И этот текущий X случайно оказывается равным нулю (или стал равным нулю в результате исчезновения порядка). Есть два варианта действий:

1. Дальнейший счет невозможен, поэтому работу программы прекратить. Юзер останется в восторге.

2. Обработать деление на ноль, сдвинуть текущее значение X (например, на машинное эпсилон) и продолжить решение. С ОЧЕНЬ большой вероятностью корень таки будет найден. Юзер тоже останется в восторге.


 
Суслик ©   (2007-02-24 01:49) [88]


> Юрий Зотов ©   (24.02.07 01:45) [87]
> > Суслик ©   (24.02.07 00:31) [84]
>
> Дим, ты еще никогда не был так прав, как в [84]

Это намек? :)


> Пример навскидку. Представь, что ты ищешь корень уравнения
> <skiped>
> тоже останется в восторге.

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

Почему придираюсь? Да просто потому, что наследование от EMathError ничего не говорит о "гибкости и удобстве использования своей библиотеки".
Все. Собственно - я ни на что более не претендую :)


 
vuk ©   (2007-02-24 10:02) [89]

to Юрий Зотов ©   (24.02.07 01:30) [86]:
>Например, Rx, Dx, DC, FR, EhGrid, FC и другие.
Юр, FR - это FastReport? Если да, то выкидывай из списка. У него там сплошняком следующее:

Obj := TSomeClass.Create(...);
//Разные действия
Obj.Free;

То есть обработки исключений в таких случаях нет вообще. Похоже, что из принципа. Я самую последнюю (4.х) версию не видел, но в предпоследней (3.х) все было по-прежнему.


 
Anatoly Podgoretsky ©   (2007-02-24 12:42) [90]

> Loginov Dmitry  (24.02.2007 00:09:22)  [82]

> я ведь разрабатываю open-source - инструментарий, и уровень конечно должен быть соответствующим

Это точно и большинство open-source оправдывают это.


 
Ketmar ©   (2007-02-24 13:01) [91]

> Loginov Dmitry ©   (24.02.07 00:09) [82]
>  я ведь разрабатываю open-source

не надо.


 
Суслик ©   (2007-02-24 13:16) [92]

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

Поэтому я вообще скептически отношусь к советам, как писать хороший код.

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

PS Для опенсорсной разработки приведенная библиотека не дотягивает по уровню. И не ИМХО.


 
Loginov Dmitry ©   (2007-02-24 23:54) [93]

Насчет обработки исключений. Правильно Суслик [81], [88] говорит, наследование от EMathError ровным счетом не даст ничего. Это ничем не лучше, чем наследоваться от Exception и не сможет сделать систему более гибкой.


> [87] Юрий Зотов ©   (24.02.07 01:45)


Юрий, очень хороший пример, причем без строчки кода. Теперь мне стало ясно, что некоторые классы исключений действительно в некоторых случаях очень важны. Спасибо! (И Юрию, и Дмитрию). Буду менять механизм обработки исключений. Уже начал строить иерархию исключений. Получается примерно следующее:


type
  EMatrixError = class(Exception);
  {....}
  end;

  EMatrixErrorClass = class of EMatrixError;

  EMatrixIntError = class(EMatrixError);
  EMatrixEDivByZero = class(EMatrixIntError);

  EMatrixMath = class(EMatrixError);
  EMatrixZeroDivide = class(EMatrixMath);

  EMatrixUnderflow = class(EMatrixMath);
  EMatrixWrongCoord = class(EMatrixError);
  EMatrixAbstractError = class(EAbstractError);


В класс исключения EMatrixError можно добавлять поля, в которые и следует заносить дополнительную информацию (имя объекта, тип объекта, последовательность вызовов процедур, приведшая к ошибке, и т.д.). Дополнительные поля можно будет использовать, а можно и не обращать внимание на содержащуюся в них информацию. Код станет даже короче. Различные процедуры Matrix32 так и будут заворачиваться в блок try...except. Примерно так:


procedure TMatrix.Foo;
begin
  try
    if C = 0 then
      raise EMatrixZeroDivide.Create("Ошибка деления на ноль!")
  except
    on E: Exception do
      RaiseMatrixError(E, "procedure TMatrix.Foo");
  end;
end


Но функция RaiseMatrixError будет переписана. Примерно так:


procedure RaiseMatrixError(Error: Exception; const FunctionName: string);
var
  NewError: EMatrixError;
begin
  if Error is EMatrixError then
  begin
    NewError := EMatrixError.Create(Error.Message);
    NewError.FunctionList := FunctionName + " -> " + NewError.FunctionList;
  end else
  begin
    if Error is EDivByZero then
    begin
      NewError := EMatrixDivByZero.Create(Error.Message);
      NewError.FunctionList := FunctionName;
    end else if Error is EZeroDivide then
    begin
      NewError := EMatrixZeroDivide.Create(Error.Message);
      NewError.FunctionList := FunctionName;
    end else
    begin
      NewError := EMatrixError.Create(Error.Message);
      NewError.FunctionList := FunctionName;
    end;
  end;
  raise NewError;
end;


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


procedure RaiseMatrixError(Error: Exception; const FunctionName: string);
var
  NewError: EMatrixError;
begin
  NewError := EMatrixError.Create(Error.Message);
  NewError.ErrorClass := Error.ClassType;

  if Error is EMatrixError then
    NewError.FunctionList := FunctionName + "->" + NewError.FunctionList
  else
    NewError.FunctionList := FunctionName;    

  raise NewError;
end;


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


try
  with TByteMatrix.Create do
  try
    Resize([1]);
    FillByValue(100);
    ValueOperation(ThisMatrix, 0, opDiv);
  finally
    Free;
  end;
except
  on E: EMatrixError do
  begin
    if E.ErrorClass is EDivByZero then
      ShowMessage("Деление на ноль в результаты выполнения процедур: " + E.FunctionList);
  end;
end;


Юрий, я представил выше два возможных варианта обработки исключений в Matrix32. Как вы считаете, какой из вариантов может иметь право на существование? (Представленные мною варианты конечно весьма сыроваты, но смысл надеюсь понятен).


 
Ketmar ©   (2007-02-25 00:28) [94]

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


 
Игорь Шевченко ©   (2007-02-25 00:30) [95]

Суслик ©   (23.02.07 11:47) [76]


> type
>   TMatrix = class
>      public type EException = class abstract(Exception);
>
>      public type EWrongCoord = class sealed(EException);
>
>      public procedure GetValue(const aRow, aCol: Integer):
>  Integer;
>      strict private function fValidCoord(const aRow, aCol:
>  Integer): Boolean;
>   end;  


Переведи пожалуйста фрагмент для бестолковых. Например, зачем типы объявлены внутри класса, зачем EException объявлен, как абстрактный, зачем от EWrongCoord нельзя наследоваться и зачем функция fValidCoord во-первых, названа так, во-вторых объявлена как strict private.

Мне на самом деле интересно.


 
Ketmar ©   (2007-02-25 00:33) [96]

как всё запущено...


 
Юрий Зотов ©   (2007-02-25 00:36) [97]

> Loginov Dmitry ©   (24.02.07 23:54) [93]

Дмитрий, во-первых я не понимаю. Вы говорите: "наследование от EMathError ровным счетом не даст ничего. Это ничем не лучше, чем наследоваться от Exception и не сможет сделать систему более гибкой".

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

Как это понять?

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

У исключений ДРУГАЯ концепция, прямо противоположная концепции предварительных проверок данных.

И в-третьих, я еще раз не понимаю. Приведенный код, честно говоря, сильно напоминает изобретение велосипеда сидя в песочнице. Вот и не пойму - а на фига?

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

Вводим в библиотеку функцию GetCallStack (которая выдает стек вызовов вплоть до себя самой) и документируем ее. Все, больше ничего не надо. Юзер (если хочет) использует ее так:

try
 ...
except
 GetCallStack;
 raise
end;

Просто, как веник. Так на фига ж мудрить?


 
Суслик ©   (2007-02-25 00:39) [98]


> Переведи пожалуйста фрагмент для бестолковых. Например,
> зачем типы объявлены внутри класса, зачем EException объявлен,
>  как абстрактный, зачем от EWrongCoord нельзя наследоваться
> и зачем функция fValidCoord во-первых, названа так, во-вторых
> объявлена как strict private.


1. Зачем abstract? (она правда в д2006 есть как ключевое слово, но пока не делает то зачем создан). Данное ключевое слово показывает, что для того, чтобы создать класс исключение, то нужно отнаследовать от EException, т.к. инстанцировать EException нельзя - по идее (сейчас этого нет) компилятор не должен дать этого сделать.
2. Зачем sealed? (это ключевое слово в д2006 работает корректно).
Потому как разработчик, т.е. я, разработал библиотеку таким образом, что EWrongCoord является конечным листом в иерархии. Т.е. это своего рода хинт в понимании кода - это конечный лист, в дизайне других потомков не предполагается.
3. Зачем внутри класса?
Ну здесь понятно - лишняя детализация в namespace"ах имхо еще никому не вредила. ИНаче тебе пришлось бы придумывать более информативные имена классам.
4. Почему fValidCoord?
Это же был пример :) Ну это проверка координат. Там еще были предполагаются методы.
5. Почему strict private?
Если это личный член, зачем его делать видимым другим членам модуля? Инкапсуляция, е-мое.


 
Суслик ©   (2007-02-25 00:48) [99]


> Вводим в библиотеку функцию GetCallStack (которая выдает
> стек вызовов вплоть до себя самой) и документируем ее. Все,
>  больше ничего не надо. Юзер (если хочет) использует ее
> так:
>
> try
>  ...
> except
>  GetCallStack;
>  raise
> end;


Э... Юра ты с javой не перепутал? Такую функцию просто так не создашь :)

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

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

В итоге можно получить такое сообщение (например)
1. Указанный цвет не существует.
2. Ошибка работы со стилем "Деньги"
3. Ошибка работы с таблице стилей.
4. Ошибка работы со закладкой "Доходы".
5. Ошибка работы с файорм "бла-бал.xls".

(это пример).

Более того, аналогичный стек у меня строится и для пользователя. Он в настройках может отключить показ полного стека - будет показываться только головное сообщение (в приведенном примере это "Указанный цвет не существует"). Но не это главное! Главное то, что каждый уровень может нести доп. информацию. В частности у меня есть такой функционал. Представь:
1. Есть объект (с кучей вложенных объектов любого уровня).
2. Есть ГУИ (ясное дело, что это неплохо разделено).
3. В объекте возникает в одном из полей ошибка.
4. Строится стек исключений.
5. ГУИ по стеку исключений находит визуальный компонент, который отвечает за поле, вызвавшее ошибку.


 
Игорь Шевченко ©   (2007-02-25 00:52) [100]

Суслик ©   (25.02.07 00:39) [98]


> Данное ключевое слово показывает, что для того, чтобы создать
> класс исключение, то нужно отнаследовать от EException


Я, Дима, спрашивал не что то или иное слово означает, и как оно работает, а зачем сделано именно так, а не иначе, например, как у Юры Зотова в его коротком коде (номер поста сейчас не приведу, на второй странице, по-моему).


> Ну здесь понятно - лишняя детализация в namespace"ах имхо
> еще никому не вредила. ИНаче тебе пришлось бы придумывать
> более информативные имена классам.


То есть, тебе придется в обработчике писать
on E: TMatrix.EWrongCoord do
 ...

или on E: TMatrixDescendant.EWrongCoord do
 ...

Я верно понимаю, на наследников эти типы тоже распространяются ?


 
Юрий Зотов ©   (2007-02-25 01:06) [101]

> Суслик ©   (25.02.07 00:48) [99]

> Такую функцию просто так не создашь :)

Я тоже удивился. Но раз автор УЖЕ строит стек - значит, инструмент для этого он УЖЕ имеет? Вот он и есть та самая функция.

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


 
Суслик ©   (2007-02-25 01:36) [102]


> Юрий Зотов ©   (25.02.07 01:06) [101]

Ну я тебе 3мя или 4мя постами ранее объяснил, почему свой стек имеет место быть.

Хотя ПОЛностью согласен, что для разработчика JEDI будет достаточно и более чем.


 
Loginov Dmitry ©   (2007-02-25 07:46) [103]

>
> try
> ...
> except
> GetCallStack;
> raise
> end;


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

procedure RaiseException(AText: string; ExceptClass: TExceptionClass);
begin
 {1. Обнуляем список для GetCallStack}
 {2. Генерируем исключение}
end;

Хотя трудности с тем, как вовремя очистить список еще будут.


 
Ketmar ©   (2007-02-25 10:25) [104]

нет тут никаких трудностей. ибо список давно сделан. и управляется автоматически. смотреть по адресу SS:ESP.


 
Loginov Dmitry ©   (2007-02-26 15:46) [105]

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


Откуда, интересно, я должен был знать о таких вот возможностях JEDI. Вот скачал, посмотрел, теперь знаю, что изобретаю велосипед. JEDI позволяет узнать не только текст ошибки но всю последовательность вызовов функций, адреса и номера строк, в которых ошибка возникла, обрабатывалась (использовались блоки try..except, try..finally), имя модуля, файл модуля. Понравилось :)
Блин, чтож мне теперь всю "обработку" ошибок у себя удалять что-ли? Жалко... :(


 
Jeer ©   (2007-02-26 15:50) [106]

Loginov Dmitry ©   (26.02.07 15:46) [105]

> теперь знаю, что изобретаю велосипед


Так давно сказано было насчет велосипеда в треугольными колесами.


 
Loginov Dmitry ©   (2007-02-26 15:53) [107]

Говорят то все, а убедить могут только очень немногие.


 
Jeer ©   (2007-02-26 16:02) [108]


> Loginov Dmitry ©   (26.02.07 15:53) [107]


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


 
Ketmar ©   (2007-02-26 16:08) [109]

> Loginov Dmitry ©   (26.02.07 15:53) [107]
> Говорят то все, а убедить могут только очень немногие.

так это потому, что линейкой по рукам в виртуале не получается.


 
Сергей М. ©   (2007-02-26 16:34) [110]


> Loginov Dmitry ©   (26.02.07 15:53) [107]


Ты ж с TMyThread.Create(..).Terminate намедни облажался по полной программе, продемонстрировав полное нежелание/неумение пользовать встр.отладчик, что уж там говорить про идеологию/концепцию/реализацию метода Free ?) Кто после этого будет "убеждать" тебя ?)


 
Loginov Dmitry ©   (2007-02-26 19:58) [111]

> [110] Сергей М. ©   (26.02.07 16:34)


Ну спасибо! Вот похвалил!

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


{$DEFINE CanChangeExceptionMessage}
try
 C := 0;
 A := B / C;
except
 on E: Exception do
 begin
   {$CanChangeExceptionMessage WriteCallStack}E.Message := E.Message + sLineBreake + FunctionName;{$ENDIF}
   raise;
 end;
end;


И все дела :)
Никакого изобретения велосипедов. И в тоже время можно без проблем пользоваться средствами JEDI.
Вот блин! Столько возни, а разгадка была совсем рядом :))


 
Eraser ©   (2007-02-26 20:08) [112]

> [111] Loginov Dmitry ©   (26.02.07 19:58)


> И все дела :)
> Никакого изобретения велосипедов

как раз наоборот ))

не приведи Господь потом код разгребать после вот таких девелоперов )


 
Loginov Dmitry ©   (2007-02-26 20:29) [113]

Ну тут-то какие претензии могут быть? Я почти совсем уже не вмешиваюсь в обработку исключений. Выключи опцию CanChangeExceptionMessage (тогда уже вмешательства не будет абсолютно никакого) и обрабатывай исключения как хочешь. Это, я считаю, ГОРАЗДО лучше, чем было раньше.


 
Loginov Dmitry ©   (2007-02-26 22:09) [114]

И тут обломался :(

Оказывается нельзя изменить текст у исключений, генерируемых ОС.


 
Ketmar ©   (2007-02-26 22:20) [115]

и это правильно.


 
Anatoly Podgoretsky ©   (2007-02-27 00:45) [116]

> Loginov Dmitry  (26.02.2007 15:53:47)  [107]

Вот когда будут убеждать рублем, то эффект будет налицо.


 
Ketmar ©   (2007-02-27 01:06) [117]

> Anatoly Podgoretsky ©   (27.02.07 00:45) [116]
неа. будут темы "а мне зряплату дали не всю! зато всё лицо набили..."


 
Loginov Dmitry ©   (2007-02-28 21:22) [118]

Вернемся к велосипедам.
Есть два варианта регенерации исключения:

1)

procedure Foo;
begin
 try
   raise Exception.Create("Ошибка!");
 except
   on E: Exception do
   begin
     MatrixCorrectExceptMsg(E, "procedure Foo");
     raise;
   end;  
 end;
end;


2)

procedure Foo;
begin
 try
   raise Exception.Create("Ошибка!");
 except
   on E: Exception do
     raise ReCreateExceptObj(E, "procedure Foo");
 end;
end;


Оба варианта хороши, но есть достоинства и недостатки.

Первый вариант не трогает объект исключения "Е". Он лишь форматирует текст исключения определенным образом. Соответственно raise работает с этим же объектом исключения. Недостаток данного способа - громоздкость записи (каждый раз добавлять begin...end - несколько неудобно и некрасиво).

Второй вариант пересоздает объект исключения заново. В результате после генерации исключения получим исключение того же класса, что и "Е", но это уже будет другой объект. К тому же данный подход не учитывает, что у некоторых классов исключений есть дополнительные поля (например у EHeapException), и что плохого будет, если эти поля оставить нулевыми - неизвестно. Плюсы второго способа - получается объект исключения того же класса, что и ранее; код выглядет более коротко и более красиво.

Еще есть третий вариант

3)

function Foo: Integer;
begin
 Result := 0;
 try
   raise Exception.Create("Ошибка!");
 except
   on E: Exception do ReRaiseMatrixError(E, "procedure Foo");
 end;
end;


Третий вариант аналогичен второму, и выглядет более коротко. Однако ему присущи недостатки:
- компилятор не знает, что функция ReRaiseMatrixError в результате своей работы сгенерирует исключение, поэтому пишет варнинги, если в функции Foo не выполнить инициализацию Result за пределами оператора try...except.
- Такой код сложнее отлаживать с помощью все того-же JEDI, т.к. исключение генерируется в какой-то сторонней функции ReRaiseMatrixError.

На каком варианте (1) или (2) остановиться - я не знаю. Корректно ли использование второго варианта в любых ситуациях - не знаю. Полагаюсь на ваши советы. (Боюсь опять поити в ложном направлении).


 
Игорь Шевченко ©   (2007-02-28 21:29) [119]

Loginov Dmitry ©   (28.02.07 21:22) [118]

Тут в соседней ветке Алекс Коншин пишет про исключения - почитай, оно интересно


 
Loginov Dmitry ©   (2007-02-28 22:16) [120]

> Тут в соседней ветке Алекс Коншин пишет про исключения -
> почитай, оно интересно


Интересно конечно. Постараюсь в эти технологии трассировки стэка вникнуть поскорее.
Но хотелось бы ответа на вопрос [118].


 
Аноним   (2007-03-01 00:12) [121]


> Постараюсь в эти технологии трассировки стэка вникнуть поскорее.
>  

Если вникнешь, надобность ответа на [118] отпадет сама собой


 
Loginov Dmitry ©   (2007-03-03 12:12) [122]

Потратил весьма много времени на надлежащее изменение исходников Matrix32. Были учтены все советы и критика, имевшая место в данной ветке. Работа с исключениями улучшена (причем коренным образом). Многие функции по-прежднему обернуты в try...except, однако смысл такой обертки меняется в зависимости от директивы условной компиляции RecreateEObj. Если директива включена, то объект исключения пересоздается, причем в текст исключения может быть добавлена отладочная информация. Если директива выключена, то оператор try...except компилируется как:

try
....
except
  on E: Exception do
    raise;
end;


То есть фактически получаем Stack frame, который к тому же может быть очень полезным при использовании отладочных средств (jcl, библиотека отладки от Алекса Коншина). Также при выключенной опции RecreateEObj размер ехе-шника уменьшается примерно на 5 Кбайт.

Также немало внимания было уделено оформлению кода. Теперь код Matrix32, я считаю, вполне соответствует общепризнанным стандартам.

Ссылка также:

http://matrix.kladovka.net.ru/download.php?getfilename=uploads/heart/matrix32.zip

Интересно было бы узнать, чем же теперь библиотека недотягивает до open-source - инструментария? (Кроме недостатка в объемах тестирования)


 
euru ©   (2007-03-03 12:53) [123]


> Loginov Dmitry ©   (03.03.07 12:12) [122]
Сразу скажу, исходники я не смотрел. Но как по типу исключения Exception программа определит, что именно вызвало исключение?


 
Loginov Dmitry ©   (2007-03-03 12:56) [124]

Есть тип исключения. Есть текст исключения. Есть стек вызовов. Что еще нужно?


 
Ketmar ©   (2007-03-03 13:31) [125]

интересные люди.
except
 raise;
end;

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


 
Loginov Dmitry ©   (2007-03-03 13:58) [126]

от D7 не удаляет. А вообще - не принципиально. Пусть хоть удаляет. Stack frames всегда можно и в опциях проекта включить.


 
Ketmar ©   (2007-03-03 14:07) [127]

точно так же, как и отладчик. в этом случае нафиг нужны трассировки?


 
Loginov Dmitry ©   (2007-03-03 21:22) [128]

А кстати: GUID для определения живочести ссылки рулит не по децки (глобальный список вообще курит в стороне), если создать миллиончик объектов TMatrix (в гуидами это добро создается на секунду, с глобальным списком - не менее часа) (это так, навеяло веткой http://delphimaster.net/view/15-1172930690/) :))
P.S. [122] пост проигнорили конкретно :(


 
Loginov Dmitry ©   (2007-03-03 21:26) [129]

Хотя вру все-таки. Убрал проверку IndexOf, и скорость стала одинаковой :)



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

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

Наверх





Память: 1.22 MB
Время: 0.06 c
15-1172600124
Kerk
2007-02-27 21:15
2007.03.25
За что я люблю Perl


2-1172738397
МегаПупс
2007-03-01 11:39
2007.03.25
Работа с файлами


1-1170144704
Yevgeny
2007-01-30 11:11
2007.03.25
Выбор в DBGrid по Shift-LeftClick


15-1172439246
Riply
2007-02-26 00:34
2007.03.25
Ничавойное состояние.


2-1172959193
San1
2007-03-04 00:59
2007.03.25
EConvertError





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