Re[17]: Checked exceptions... зло или добро?
От: Cyberax Марс  
Дата: 19.07.05 03:20
Оценка:
VladD2 wrote:

> C>В Яве/C# исключение может вылететь в любой момент (какой-нибудь

> C>OutOfMemory), а в С++ можно гарантировать, что функции не кинут
> исключения.
> На самом деле OutOfMemoryException вылетают не в C# или еще где, а в
> CLR или ОС. Точно так же они вылетают в ОС от того же МС. Только
> вылетают они в виде SEH и по-умолчанию не ловятся С++-ными catch-ами.
> Это в свою очередь приводит к полному падению приложения.

void *__cdecl operator new(size_t size) _THROW1(_STD bad_alloc)
{       // try to allocate size bytes
        void *p;
        while ((p = malloc(size)) == 0)
                if (_callnewh(size) == 0)
                        _STD _Nomemory();
        return (p);
}
...
_CRTIMP2 void __cdecl _Nomemory()
    {    // report out of memory
    static const _XSTD bad_alloc nomem;
    _RAISE(nomem);
    }
...

То есть в VC будет кидаться std::bad_alloc (по Стандарту), причем
исключение создается на стеке и не занимает динамическую память.

> Ну, да при OutOfMemoryException уже мало что можно поделать. Памяти то

> нет и обрабатывать исключение просто не чем.

А автоматическое хранилище (aka stack) на что? Кстати, в случае OOM
вполне можно почистить какие-нибудь кэши и спокойно жить дальше. Так
делалется, например, в Tangasol Coherence.

--
С уважением,
Alex Besogonov (alexy@izh.com)
Posted via RSDN NNTP Server 1.9
Sapienti sat!
Re[12]: Checked exceptions... зло или добро?
От: Cyberax Марс  
Дата: 19.07.05 03:21
Оценка:
VladD2 wrote:

> E>будет генерировать исключения или нет. Конечно, можно

> перестраховаться и все неизвестные функции в try/catch обрамлять
> (особенно в деструкторах). Но ведь это overhead не слабый получается.
> А зачем обрамлять то? Пропускай их и все. Если появится код которому
> по его логие потребуется обработать исключение, то он и будет знать
> что и как обрабатывать.

А откуда он будет это знать?

--
С уважением,
Alex Besogonov (alexy@izh.com)
Posted via RSDN NNTP Server 1.9
Sapienti sat!
Re[18]: Checked exceptions... зло или добро?
От: Cyberax Марс  
Дата: 19.07.05 03:24
Оценка: +1
Павел Кузнецов wrote:

> NullReferenceException — типичная логическая ошибка. Внешнему коду

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

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

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

--
С уважением,
Alex Besogonov (alexy@izh.com)
Posted via RSDN NNTP Server 1.9
Sapienti sat!
Re[15]: Checked exceptions... зло или добро?
От: IT Россия linq2db.com
Дата: 19.07.05 04:53
Оценка: :)
Здравствуйте, Cyberax, Вы писали:

C>Смотрели, чтобы оно было обработано.


Могу им подарить один универсальный способ:

try
{
  DoWhateverYouWant();
}
catch (Exception ex)
{
}

Готово. Может они что-то особенное делали в catch?

C>Просто эти товарищи пишут 24x7 систему, которая должна работать как можно безглючнее.


Это я понимаю. Но я не понимаю общности слова обработать. Записать в лог? Ну так для этого вышеприведённый вариант очень даже здорово подходит. Отослать на e-mail админу? То же самое.

C>У них это, кстати, получилось. За мой опыт работы с Tangasol

C>Coherence'ом мне его свалить не удалось ни разу.

Это очень здорово. Не могу только понять зачем нужно отдельно обрабатывать каждый тип исключений.
... << RSDN@Home 1.2.0 alpha rev. 0>>
Если нам не помогут, то мы тоже никого не пощадим.
Re[16]: Checked exceptions... зло или добро?
От: Cyberax Марс  
Дата: 19.07.05 05:02
Оценка:
IT wrote:

> C>Смотрели, чтобы оно было обработано.

> Могу им подарить один универсальный способ:
>
>try
>{
> DoWhateverYouWant();
>}
>catch (Exception ex)
>{
>}
>
>
Это называется "проигнорировано", а не "обработано".

> Готово. Может они что-то особенное делали в catch?


Естественно.

> C>Просто эти товарищи пишут 24x7 систему, которая должна работать как

> можно безглючнее.
> Это я понимаю. Но я не понимаю общности слова обработать. Записать в
> лог? Ну так для этого вышеприведённый вариант очень даже здорово
> подходит. Отослать на e-mail админу? То же самое.

А как насчет прибить поврежденные данные и пересинхронизировать их с
других узлов?

> C>У них это, кстати, получилось. За мой опыт работы с Tangasol

> C>Coherence'ом мне его свалить не удалось ни разу.
> Это очень здорово. Не могу только понять зачем нужно отдельно
> обрабатывать каждый тип исключений.

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

--
С уважением,
Alex Besogonov (alexy@izh.com)
Posted via RSDN NNTP Server 1.9
Sapienti sat!
Re[17]: Checked exceptions... зло или добро?
От: IT Россия linq2db.com
Дата: 19.07.05 05:23
Оценка: 3 (1) +2
Здравствуйте, Cyberax, Вы писали:

C>Это называется "проигнорировано", а не "обработано".


Именно.

>> Готово. Может они что-то особенное делали в catch?


C>Естественно.


Вот это самое интересное.

C>А как насчет прибить поврежденные данные и пересинхронизировать их с

C>других узлов?

Для прибить (и даже восстановить) существуют такие вещи как транзакции. Что такое переиндексировать их с других узлов мне не совсем понятно.

C>Нужно следить не столько за типами исключений, сколько за возможностью вылета "прикладных" исключений.


Т.е. своих собственных?

C>То есть не логических ошибок в коде, а исключительных ситуаций в процессе работы.


Не пугай меня. Это называется строить логику программы на исключениях. Объектно-ориентированный longjump. Никакого отношения к надёжности программы это не имеет.

В общем, пока совершенно не понятно зачем нужно обрабатывать абсолютно все исключения.
... << RSDN@Home 1.2.0 alpha rev. 0>>
Если нам не помогут, то мы тоже никого не пощадим.
Re[16]: Checked exceptions... зло или добро?
От: Павел Кузнецов  
Дата: 19.07.05 05:25
Оценка:
Cyberax,

ПК>> class C1 : I

ПК>> {
ПК>> void f() // или что надо написать, чтоб реализовать I::f...
ПК>> {
ПК>> throw new Exception1();
ПК>> }
ПК>> };

C> В случае с checked exceptions — ошибка компиляции.


Подожди... А что там компилятор нагенерил-то уже, и по какому критерию?
Posted via RSDN NNTP Server 2.0 beta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[17]: Checked exceptions... зло или добро?
От: Cyberax Марс  
Дата: 19.07.05 05:37
Оценка:
Павел Кузнецов wrote:

> ПК>> class C1 : I

> ПК>> {
> ПК>> void f() // или что надо написать, чтоб реализовать I::f...
> ПК>> {
> ПК>> throw new Exception1();
> ПК>> }
> ПК>> };
> C> В случае с checked exceptions — ошибка компиляции.
> Подожди... А что там компилятор нагенерил-то уже, и по какому критерию?

То есть? Не понял вопроса.

--
С уважением,
Alex Besogonov (alexy@izh.com)
Posted via RSDN NNTP Server 1.9
Sapienti sat!
Re[12]: Checked exceptions... зло или добро?
От: Павел Кузнецов  
Дата: 19.07.05 05:39
Оценка: +3
Cyberax,

C> А насколько нужна изоляция? Какой-нибудь null-pointer-exception через

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

Я отношусь к тем, кто считает, что в таком случае null-pointer-exception имеет особенно
мало смысла: если вызывающий код готов к null-pointer-exception, то почему он вообще
передал нулевой указатель? Если не готов, то как ему поможет null-pointer-exception?
Posted via RSDN NNTP Server 2.0 beta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[13]: Checked exceptions... зло или добро?
От: Cyberax Марс  
Дата: 19.07.05 06:00
Оценка:
Павел Кузнецов wrote:

> C> А насколько нужна изоляция? Какой-нибудь null-pointer-exception через

> C> несколько уровней потеряет всякий смысл, в нем не будет полезной
> C> информации для попытки восстановить выполнение.
> Я отношусь к тем, кто считает, что в таком случае
> null-pointer-exception имеет особенно
> мало смысла: если вызывающий код готов к null-pointer-exception, то
> почему он вообще
> передал нулевой указатель? Если не готов, то как ему поможет
> null-pointer-exception?

ОК, пусть будет не NullPointerException (которых в С++ все равно нет
), а connection_refused_exception. То есть исключение, обозначающее
прикладную ошибку.

--
С уважением,
Alex Besogonov (alexy@izh.com)
Posted via RSDN NNTP Server 1.9
Sapienti sat!
Re[9]: Движутся ли mainstream языки в сторону лиспа?
От: mishaa Россия http://kmmbvnr.livejournal.com
Дата: 19.07.05 06:53
Оценка: 1 (1)
Здравствуйте, VladD2, Вы писали:


VD>до тех пор пока во втором фрэйморке не ввели TryParse который просто возвращает булево значение вместо того чтобы кидать исключение. В итоге проблема исчезла. И никакие checked exceptions не понадобились. А все потому, что при проектировании в Parse была изначально заложена ошибка (вренее скопирована с Явы). Ошибка банальная... Неверные данные в Parse/parseInt очень часто бывают не исключительно, а совершенно шаттной ситуацией.


Вобшем понятно, тут дело к свяшенной войне идет, что значить ИСКЛЮЧИТЕЛЬНАЯ ситуация, а уж checked она должна быть или unchecked это уже из ее определения будет видно.

Кстати может кто-нибудь попытается сформулировать какое-нибудь обобшенное определение?

Кстати возврашаясь к Лиспу, т.к. там при "исключении" (ну а точнее сигнале) стек может и не уничтожатся, объекты под GC не попадают, и есть возможность продолжить с того же места, так что понятие той самой ИСКЛЮЧИТЕЛЬНОЙ ситуации для него будет IMHO неприменимо.
-- Главное про деструктор копирования не забыть --
Re[11]: Движутся ли mainstream языки в сторону лиспа?
От: pvgoran Россия  
Дата: 19.07.05 10:59
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:

ПК>pvgoran,


>> IM(very)HO checked exceptions лучше рассматривать как альтернативный механизм возврата значений из функции — и использовать соответствующим образом.


ПК>В таком случае вопрос: причем к возврату значений из функции механизм обработки исключительных ситуаций?


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

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

Дргой пример — доступ к ассоциативному контейнеру без автосоздания элементов. Нормальный исход — когда элемент есть и доступ предоставлен, альтернативный исход — когда элемента нет.

ПК>Основная особенность исключений направлена на решение следующей проблемы: код, непосредственно вызывающий потенциально бросающую функцию обычно не в состоянии обработать исключительную ситуацию, и, соответственно, незачем его "заморачивать" обработкой всевозможных кодов возврата и т.п. Исключение можно обработать где-то наверху. Диагностируется оно (обычно) где-то глубоко внизу. Соответственно, механизм обработки исключений "заточен" именно на такой сценарий. throw — внизу, try catch — вверху, ничего в таком духе — между.


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

В языках вроде OCaml'а подобные вещи можно сделать, создавая специальные типы. В C++/Java можно использовать исключения (хотя они и предназначены не только и, может быть, не столько для этого).

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


Не совсем точно. Остается еще независимость типа/содержания исключения от типа/содержания возвращаемого значения.

ПК> Но даже эта выгода серьезно подрывается дизайном checked exceptions в Java: количество try catch, которое люди "лепят", чтоб "обернуть" и т.п.

ПК>исключения на промежуточных уровнях, приводит к периодическому "проглатыванию" исключений.

OK.

ПК>Применительно же к уже существующим реализациям, не содержащим ничего, аналогичного checked exceptions (C++, .Net и т.п.), их введение post factum, вообще, кажется нереальным: имхо, польза от (гипотетически более удачного дизайна, чем в Java) checked exceptions будет только в случае, если это последовательно исполняется на всех уровнях, чего уже нет. Ревизия огромного количества существующего кода для добавления отсутствующих exception specifications, имхо, неосуществима.


Согласен.

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


Можно немного поспекулировать на эту тему... Например: сделаем exception specification частью сигнатуры функции (если это еще не сделано) и позволим задавать их с помощью списков типов a-la Александреску. Причем предусмотрим template instantiation matching с участием этих списков. Таким образом, например, можно сделать boost::bind "прозрачным" с точки зрения спецификаций исключений.

Хотя, похоже, это только начало. Нужно еще ввести запросы компилятору вида "какие исключения может выдать вызов функции/объекта с параметрами данного типа"... Если подумать об объеме кода, нужного, чтобы это все задекларировать, становится страшновато... (Наверное, так же страшно программистам на динамически типизированных языках представить наличие спецификаций типов. )
... << RSDN@Home 1.1.4 stable rev. 510>>
Re[18]: Checked exceptions... зло или добро?
От: Павел Кузнецов  
Дата: 19.07.05 13:39
Оценка:
Cyberax,

ПК>>>> class C1 : I

ПК>>>> {
ПК>>>> void f() // или что надо написать, чтоб реализовать I::f...
ПК>>>> {
ПК>>>> throw new Exception1();
ПК>>>> }
ПК>>>> };

C>>> В случае с checked exceptions — ошибка компиляции.


ПК>> Подожди... А что там компилятор нагенерил-то уже, и по какому критерию?


C> То есть? Не понял вопроса.


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


Вот я и спрашиваю: раз ты предполагаешь, что компилятор в данном случае должен был посчитать, что f()
имеет пустую спецификацию исключений, то по какому алгоритму он действовал?
Posted via RSDN NNTP Server 2.0 beta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[18]: Checked exceptions... зло или добро?
От: Left2 Украина  
Дата: 19.07.05 15:39
Оценка:
>> Ну, да при OutOfMemoryException уже мало что можно поделать. Памяти то нет и обрабатывать исключение просто не чем.

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


+ в приложениях, которые должны работать в условиях ограниченной памяти память для обработчика OutOfMemoryException выделяется (резервируется) заранее, в самом начале работы приложения. Так что это не проблема ни в C++, ни в C#.
... << RSDN@Home 1.1.4 stable rev. 510>>
Re[18]: Checked exceptions... зло или добро?
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 19.07.05 15:54
Оценка: +1
Здравствуйте, Павел Кузнецов, Вы писали:

ПК>-1. При недостаче памяти в C++ вылетает std::bad_alloc.


Даже если памяти не хватило внутри апишной функции?

>> Ну, да при OutOfMemoryException уже мало что можно поделать. Памяти то нет и обрабатывать исключение просто не чем.


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


Гарантии нет, а без гарантии мало что построить можно.

>> А вот NullReferenceException очень даже обрабатывается. При этом в большинстве случае C#-ные приложения продолжают работать дальше, а большинство С++-ных выпадает "в осадок".


ПК>NullReferenceException — типичная логическая ошибка.


Это может быть совершенно произвольная ошибка.

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


Ты в своих программах всегда проверяешь все параметры на null? А если он таки null, что делаешь? В фреймворке в этом случае вылетает чаще ArgumentNullException. Он лучше NullReferenceException, но лишь тем что предоставляет чуть больше информации о ситуации. С точки зрения устойчивости приложения никакой разницы нет.

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


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

ПК>Это очень легко наблюдать на многих приложениях, написанных на Java и C# в случаях возникновения непредусмотренных исключительных ситуаций.


Пример таких приложений можно?
... << RSDN@Home 1.2.0 alpha rev. 580>>
AVK Blog
Re[19]: Checked exceptions... зло или добро?
От: Павел Кузнецов  
Дата: 19.07.05 16:19
Оценка: :)))
AndrewVK,

ПК>> -1. При недостаче памяти в C++ вылетает std::bad_alloc.


A> Даже если памяти не хватило внутри апишной функции?


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

ПК>> -1. После раскрутки стека и, соответственно, освобождения некоторой

ПК>> памяти вполне может образоваться нужный запас.

A> Гарантии нет, а без гарантии мало что построить можно.


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

В C++ процесс освобождения памяти вполне детерминирован. В чем проблема-то?

ПК>> NullReferenceException — типичная логическая ошибка.


A> Это может быть совершенно произвольная ошибка.


Например?

ПК>> Внешнему коду доверять странно, если он передал нулевую ссылку там,

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

A> Ты в своих программах всегда проверяешь все параметры на null? А если он

A> таки null, что делаешь?

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

A> В фреймворке в этом случае вылетает чаще ArgumentNullException.

A> Он лучше NullReferenceException, но лишь тем что
A> предоставляет чуть больше информации о ситуации. С точки зрения
A> устойчивости приложения никакой разницы нет.

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

ПК>> Попытка "восстановления" после подобной ошибки зачастую приводит к

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

A> Ни разу не сталкивался. Вон янус в настоящий момент после любых

A> необработанных исключений в процессе работы продолжает жить.

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

И так было, пока я не перезапустил приложение.

В общем, положил я его в итоге обратно в каталог Install, и больше не трогал.

ПК>> Это очень легко наблюдать на многих приложениях, написанных на Java и

ПК>> C# в случаях возникновения непредусмотренных исключительных ситуаций.

A> Пример таких приложений можно?


См. выше.
Posted via RSDN NNTP Server 2.0 beta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[19]: Checked exceptions... зло или добро?
От: Cyberax Марс  
Дата: 19.07.05 16:29
Оценка: 9 (2) +1
AndrewVK wrote:

> ПК>-1. При недостаче памяти в C++ вылетает std::bad_alloc.

> Даже если памяти не хватило внутри апишной функции?

При недостатке памяти АПИшные функции будут возвращать код ошибки.

>>> Ну, да при OutOfMemoryException уже мало что можно поделать. Памяти

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

Почему? В С++ гарантировано, что после вылета исключения о OOM
автоматическое хранилище будет работать. Потом, даже если не удастся
освободить память, то приложение умрет. А если все-таки удастся?

> ПК> Внешнему коду доверять странно, если он передал нулевую ссылку

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

Если по логике работы параметр может быть null-ом — то естественно.

> А если он таки null, что делаешь?


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

> В фреймворке в этом случае вылетает чаще ArgumentNullException. Он

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

У меня была такая ситуация: программа (на Java) читает архив с
сериализованными классами (через свой десериализатор), в процессе
десериализации одного из классов в некоторых случаях происходил глюк, в
результате которого портилась статическая (точнее thread local)
переменная и кидалось NullPointerException. Программа это исключение
вылавливала ("catch(Throwable t)") и выводила красивое окошко с ошибкой
о поврежденном файле.

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

Клиенты были сильно недовольны.

--
С уважением,
Alex Besogonov (alexy@izh.com)
Posted via RSDN NNTP Server 1.9
Sapienti sat!
Re[19]: Checked exceptions... зло или добро?
От: Павел Кузнецов  
Дата: 19.07.05 17:33
Оценка:
Left2,

>>> Ну, да при OutOfMemoryException уже мало что можно поделать. Памяти то нет и обрабатывать исключение просто не чем.


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


> + в приложениях, которые должны работать в условиях ограниченной памяти память для обработчика OutOfMemoryException выделяется (резервируется) заранее, в самом начале работы приложения. Так что это не проблема ни в C++, ни в C#.


Единственное, что в C#, действительно, мало, что изменится от того, что было выброшено OutOfMemoryException: при раскрутке стека память автоматически не освобождается, так что вся надежда на сборщик мусора. Интересно, может, он как-нибудь специально реагирует на OutOfMemoryException?
Posted via RSDN NNTP Server 2.0 beta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[20]: Checked exceptions... зло или добро?
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 19.07.05 21:06
Оценка: +1
Здравствуйте, Павел Кузнецов, Вы писали:

ПК>Имхо, попытки генерировать std::bad_exception в std::unexpected для случая throw() сродни попыткам

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

ПК>По этому поводу есть неплохое обсуждение в comp.lang.c++.moderated:

ПК>http://groups-beta.google.com/group/comp.lang.c++.moderated/browse_frm/thread/80083ac31a1188da/c40035067fafc0e8

Почитал это обсуждение. Мое плохое знание английского не позволило понять все досконально, но надеюсь, что основные моменты я уловил.
Исходя из того, что там написано, в проверках вида:
void    do_something( const char * p ) {
    if( !p )
        throw std::invalid_argument( "do_something: p == 0!" );
    ...
}

нет никакого смысла и лучше дать возможность аварийно завершиться приложению, поскольку do_something не должна получать нулевого аргумента. Звучит вполне разумно. Особенно, если учесть, что p может иметь не нулевое, но некорректное значение (например, 0xDEADCAFE, из-за повисшего или "битого" указателя).

Тем не менее, я считаю, что здесь не все так однозначно. Я исхожу из двух предпосылок.
Во-первых, нужно различать, является ли do_something частью открытого интерфейса какой-либо библиотеки, или это закрытая часть реализации библиотеки. Если это закрытая часть, то я полностью согласен с тем, что порождать исключение бессмысленно, нужно использовать assert-ы. Но вот если do_something является частью открытого интерфейса, то здесь ситуация меняется и в дело вступает вторая предпосылка.
Во-вторых, существует целый класс ошибок, связанных с передачей в качестве аргументов заведомо неправильных данных. Откуда эти данные берутся и почему они становятся аргументами -- это другой вопрос. Тем не менее, в результате совершенно не критических, а иногда даже элементарных, ошибок в do_something может быть передан нулевой указатель. Причем именно нулевой, т.к. 0 -- это валидное значение для обозначения ни на что не указывающего указателя. Например:
do_something( find_user_group_name( user_name, user_security_data ) );

Функция find_user_grop_name() возвращает имя группы, которой принадлежит пользователь. Но, если пользователь не принадлежит ни одной из групп, то find_user_grop_name возвращает 0. В данном фрагменте проблема программиста в том, что он должен был написать:
const char * group_name = find_user_group_name( user_name, user_security_data );
if( group_name )
    do_something( group_name )
else
    ...

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

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

Имхо, в случаях, когда возможна проверка на заведомо некорректные параметры (как правило, это public интерфейс какого-либо класса, библиотеки или модуля), лучше все-таки порождать исключения. Во-первых, потому, что это самая ближайшая к месту появления проблемы точка (все-таки гораздо понятнее, когда в исключении будет сказано, что это do_something и причина в нулевом значении p). А то ведь crush dump мог быть инициирован где-нибудь на три уровня вложенности ниже. А еще хуже, что он мог быть вообще не инициирован, если в текущем состоянии программы параметр p игнорируется.
Во-вторых, потому, что это дает возможность приложению, если оно спроектировано на восстановление после подобных исключений, восстановиться на каком-то уровне. Ну например, есть многопоточное приложение сервер, обрабатывающее коммуникационные сессии. В рамках обработки одного из запросов одной из сессий диагностируется подобная ошибка. Происходит проброс исключения до самого верхнего уровня обработчика данной сессии. Он понимает, что все плохо, ни на какие из прочитанных в сессии данных надеятся нельзя. Но можно отослать клиенту специальный ответ (что-то типа General Failure или Service Unavailable) после чего просто закрыть сессию и удалить все связанные с ней ресурсы. Такое поведение позволяет оставить все остальные сессии в рабочем состоянии.
А в-третих, если исключения никто не перехватит, то все равно получится тот же самый crush dump.


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

Паша, может как раз такие вещи ты и называл в числе тех редких случаев, когда после ошибки в программе восстановление еще возможно?
... << RSDN@Home 1.1.4 stable rev. 510>>


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[18]: Checked exceptions... зло или добро?
От: BorisKV  
Дата: 20.07.05 00:09
Оценка:
Здравствуйте, IT, Вы писали:

IT>Не пугай меня. Это называется строить логику программы на исключениях. Объектно-ориентированный longjump. Никакого отношения к надёжности программы это не имеет.


Да ладно тебе — ты сам на таком проекте работаешь и до этого работал — когда некоторые товарисчи вместо проверки на null ловят NullReferenceException и потом гордо считают себя супер профессионалами.

т.е. был код:
public string FormatCurrencyLocalized(decimal amount)
{
    if (Resources != null)
        return String.Format(Resources.GetString("CurrencyFormat"), amount);
        
    return String.Format("{0}:C", amount);
}


его заменяют на
public string FormatCurrencyLocalized(decimal amount)
{
        try { return Resources.GetString("CurrencyFormat") + amount.ToString("C");}
        catch { return amount.ToString("C"); }
}


причем в GetString тоже стоит try/catch block который ловит Exception (именно базовый класс) и возвращает пустую строку в случае ошибки...

Могу еще напомнить про .NET Remoting брокер с предидущего проекта и логику на том же самом NullReferenceException... В общем наверное это патерн такой про который мы с тобой у умных дядек не прочитали — Object Oriented LongJump.
... << RSDN@Home 1.1.4 beta 7 rev. 447>>
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.