Здравствуйте, IT, Вы писали:
//код примера красоты работы с исключениями поскипан
Прочитал всю тему и захотелось подлить масла в огонь (пусть я и не согласен с автором темы).
Если я не перепутал то прекрасный пример который мы видели основан на гарантиях небросания
В жизни подобные гарантии эээ "не совсем верны" так ведь ? Насколько я помню дискуссию на clcm по этому поводу
("RAII and resource release functions that can throw" Scott Meyers 20 Фев. 04:26)
в реальном коде обработки банковских транзакций придется ловить все что оттуда вылетает. (те красота в природе не встречается).
И еще один вопросик.
Сдесь была подветка по обработке "нечисел" в формулах и вычислениях. Кто нибудь может показать минимальный пример кода с использованием исключений ? А то создается впечатление что в хендлере верхнего уровня можно "угадать" результат функции по типу "нечисла" которое оттуда вылетело
Господа философы, хватит спорить о пользе исключений! Хотел бы затронуть более практическую сторону использования исключений, а именно — фильтрацию. Я уже описывал проблему в форуме С/С++, здесь
Кратко повторюсь. Exception-safe и exception-neutral код действительно очень выигрывает по сравнению с использованием возврата (кода) ошибок.
Однако в программе где-то должны быть (хотя бы один) try/catch, и тут начинаются проблемы. Прежде всего — фильтрация исключений. Исключения могут возникать на разных логических уровнях и смешивать их в кучу нельзя. Например, с нижнего уровня пришло исключение "ошибка переполнения буфера", тогда как пользователю следовало бы показать (да и в лог записать): "не удалось открыть документ, т.к. он открыт другим приложением" (пример чисто условный). Т.е. нужно как бы раскрутить стек в обратную сторону, сверху вниз, чтобы узнать, в какой функции, в какой подфункции и т.д. произошел сбой.
Но стек раскручивается в направлении снизу вверх. Чтобы добиться фильтрации исключений, т.е. подавления исключений нижнего уровня и переизлучения исключений более высокого уровня, необходимо на каждом уровне ставить ловушки try/catch. Например, оборачивать публичные методы классов и конструкторы. Однако при этом код становится менее читабельным и уже больше напоминает проверку кода возврата, т.е. теряет преимущества прозрачности и нейтральности.
Как обычно осуществляют фильтрацию исключений? Может существует какой-то хитрый способ автоматического "оборачивания" исключений на промежуточных уровнях, о котором я не знаю?
Здравствуйте, Ignoramus, Вы писали:
I>Как обычно осуществляют фильтрацию исключений? Может существует какой-то хитрый способ автоматического "оборачивания" исключений на промежуточных уровнях, о котором я не знаю?
Пардон, а чего ты ожидаешь от этого автоматического оборачивания?
В дотнете, к примеру, можно на каждом логическом уровне оборачивать исключения для указания контекста.
Примерно так:
public static Library OpenLibrary(string libId)
{
#region Arguments validation
if(libId == null)
throw new ArgumentNullException("libId");
#endregion
try
{
return libraries[libId].Open();
}
catch(IndexOutOfRange ioor)
{
throw new LibraryNotFoundException("specified library not found", libId, ioor);
}
catch(Exception e)
{
throw new LibraryException("Could not load library with id = " + libId, e);
}
}
Это означает, что вызывающий код
а) может не заморачиваться с тем, чтобы ловить абстрактные NullReferenceException, который произошел хрен знает где ниже по стеку. Вместо этого можно отлавливать более осмысленные, с его точки зрения, LibraryException и строить на них свою логику (например, попытаться загрузить дефолтную Library, чтобы это ни значило).
б) может получить информацию о причинах проявления высокоуровневого исключения через InnerException. В частности, админ (если от него это не скрыть) сможет понять, что был AccessViolation или FileNotFound.
Да, на первый взгляд это все очень плохо, т.к альтернативой был бы
public static Library OpenLibrary(string libId)
{
return libraries[libId].Open();
}
который намного короче, яснее, и удобнее в написании. К сожалению, в поддержке подобный код далеко не настолько удобен. К счастью, далеко не всегда нужно писать так много кода.
Как правило речь идет только о фасадном коде, а все внутренние потроха можно оставить в первоначальном виде. Вовсе незачем заворачивать исключение в столько же оберток, сколько методов было на стеке. Обычно обертывание полезно только при пересечении логического уровня.
1.1.4 stable rev. 510
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, IT, Вы писали:
IT>Да, кстати, использование ref и out параметров считается признаком плохого дизайна. FxCop на это заявляет "Consider a design that does not require that 'parameter_name' be an out parameter".
Если не трудно, нельзя ли раскрыть эту мысль, или носом ткните, где почитать, что плошого в ref и out параметрах?
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, Ignoramus, Вы писали:
I>>Как обычно осуществляют фильтрацию исключений? Может существует какой-то хитрый способ автоматического "оборачивания" исключений на промежуточных уровнях, о котором я не знаю? S>Пардон, а чего ты ожидаешь от этого автоматического оборачивания?
Хороший вопрос, я и пытаюсь понять, как бы я хотел чтобы это работало Надеюсь, что вы мне поможете.
S>Это означает, что вызывающий код S>а) может не заморачиваться с тем, чтобы ловить абстрактные NullReferenceException, который произошел хрен знает где ниже по стеку. Вместо этого можно отлавливать более осмысленные, с его точки зрения, LibraryException и строить на них свою логику (например, попытаться загрузить дефолтную Library, чтобы это ни значило).
Вот-вот, проблема в том, что на уровень функции OpenLibrary подымаются всякие исключения — и абстрактные, и более-менее конкретные. Хотя причины неоткрытия библиотеки вполне конкретные и информативные (например, отсутствует файл, неправильная версия и т.п.), вместо них приходится иметь дело с абстрактными вроде null reference. Ставить на них общую затычку и говорить клиенту "не удалось открыть библиотеку".
S>б) может получить информацию о причинах проявления высокоуровневого исключения через InnerException. В частности, админ (если от него это не скрыть) сможет понять, что был AccessViolation или FileNotFound.
Сможет ли он понять это без раскрутки стека сверху вниз? Точнее, чтобы понять причину сбоя требуется информация от первого метода в стеке, а не последнего, которая приходит.
S>Да, на первый взгляд это все очень плохо, т.к альтернативой был бы S>который намного короче, яснее, и удобнее в написании. К сожалению, в поддержке подобный код далеко не настолько удобен. К счастью, далеко не всегда нужно писать так много кода. S>Как правило речь идет только о фасадном коде, а все внутренние потроха можно оставить в первоначальном виде. Вовсе незачем заворачивать исключение в столько же оберток, сколько методов было на стеке. Обычно обертывание полезно только при пересечении логического уровня.
Эта грань между логическими уровнями довольна расплывчата...
Кроме того, меня интересуют следующие проблемы, связанные с исключениями. Интересно было бы услышать комментарии.
1) Если все исключения нижнего уровня все равно подавляются на текущем методе и перевыбрасывается одно исключение, свойственное данному уровню и методу, то зачем вкладывать какую-либо информацию в исключения нижнего уровня — она все равно не используется?
2) Как следствие из 1), заключение дополнительной информации в исключениях нижнего уровня имеет смысл только в том случае, если предполагается реюзать код нижнего уровня в других проектах. В таком случае, иерархии исключений разных уровней должны быть независимы, точнее нет смысла им быть зависимыми. (хотя первым побуждением есть создание единой иерархии исключений для всего приложения)
3) В каких случаях следует наследовать новый класс исключения от базового, а в каких следует лишь параметризовать его типом/сообщением?
4) Если же требуется транспортировать какое-то сообщение в исключении, как правильно это сделать на практике? Например, как организовать возможность централизованной локализации строк сообщений, загрузку их из ресурсов?
Здравствуйте, Ignoramus, Вы писали:
I>Вот-вот, проблема в том, что на уровень функции OpenLibrary подымаются всякие исключения — и абстрактные, и более-менее конкретные.
Это не так. В данном случае OpenLibrary — это "середина" стека. В нее может приезжать тоже вполне высокоуровневая информация I>Хотя причины неоткрытия библиотеки вполне конкретные и информативные (например, отсутствует файл, неправильная версия и т.п.), вместо них приходится иметь дело с абстрактными вроде null reference.
Это от того, что предыдущий слой не взял на себя работу по оборачиванию NullReferenceException во что-то более осмысленное. I>Ставить на них общую затычку и говорить клиенту "не удалось открыть библиотеку".
S>>б) может получить информацию о причинах проявления высокоуровневого исключения через InnerException. В частности, админ (если от него это не скрыть) сможет понять, что был AccessViolation или FileNotFound.
I>Сможет ли он понять это без раскрутки стека сверху вниз? Точнее, чтобы понять причину сбоя требуется информация от первого метода в стеке, а не последнего, которая приходит.
Я не знаю, с какой стороны ты считаешь методы в стеке. В нормальном случае печатается весь пакет — от высокоуровневого (не удалось сохранить документ), через средний уровень (не удалось открыть библиотеку) до самого нижнего (файл не найден).
I>Эта грань между логическими уровнями довольна расплывчата...
Нет. Если у тебя внятная архитектура, границы между слоями четко очерчены.
I>1) Если все исключения нижнего уровня все равно подавляются на текущем методе и перевыбрасывается одно исключение, свойственное данному уровню и методу, то зачем вкладывать какую-либо информацию в исключения нижнего уровня — она все равно не используется?
Используется!
Еще раз объясняю: пользователю достаточно информации о том, что чего-то сделать не удалось. Админ посмотрит в логи и сможет понять, где не хватило прав (а приложение может лезть в какое-нибудь неожиданное место), где просто убился файл, а где не удалось достучаться до сайта в сети. I>2) Как следствие из 1), заключение дополнительной информации в исключениях нижнего уровня имеет смысл только в том случае, если предполагается реюзать код нижнего уровня в других проектах. В таком случае, иерархии исключений разных уровней должны быть независимы, точнее нет смысла им быть зависимыми. (хотя первым побуждением есть создание единой иерархии исключений для всего приложения)
Совершенно верно. Иерархии исключений разных слоев не нуждаются в объединении. I>3) В каких случаях следует наследовать новый класс исключения от базового, а в каких следует лишь параметризовать его типом/сообщением?
Наследоваться имеет смысл в тех случаях, если данный тип исключения имеет смысл ловить отдельным catch(). Трудно сформулировать более точно. Когда ты начнешь писать реальный код, ты сам увидишь, есть ли ситуации, которые ты можешь обработать в рамках данного слоя. I>4) Если же требуется транспортировать какое-то сообщение в исключении, как правильно это сделать на практике? Например, как организовать возможность централизованной локализации строк сообщений, загрузку их из ресурсов?
Особой нужды в локализации исключений нижнего уровня нет. Локализация исключений, проникающих на уровень UI, делается относительно стандартными средствами: конкретный класс исключения оборудуется конструктором с соответствующими параметрами, берет шаблон строки из ресурсов, и компонует сообщение из шаблона и значений своих параметров.
1.1.4 stable rev. 510
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
S>Это от того, что предыдущий слой не взял на себя работу по оборачиванию NullReferenceException во что-то более осмысленное.
Т.е. в промышленном коде именно так и делают? Оборачивают на каждом уровне? Как именно выглядит это оборачивание — в самом начале каждого публичного метода и конструктора ставится try, а в самом конце catch с пере-throw? Иначе я не вижу способа обеспечить полный отлов всех исключений в целях их оборачивания.
S>Используется! S>Еще раз объясняю: пользователю достаточно информации о том, что чего-то сделать не удалось. Админ посмотрит в логи и сможет понять, где не хватило прав (а приложение может лезть в какое-нибудь неожиданное место), где просто убился файл, а где не удалось достучаться до сайта в сети.
При условии присутствия промежуточных оборачивателей — да. Я пытался выяснить можно ли обойтись одним try/catch на верхнем уровне и при этом получать более подробную информацию о сбое. По-видимому это невозможно .
S>Совершенно верно. Иерархии исключений разных слоев не нуждаются в объединении.
Интересно, а где лучше размещать описания классов исключений? Наверное в том же пространстве имен, что и "логический уровень", все классы которого бросают одни и те же исключения? Не выделять в отдельный namespace Exceptions?
I>>4) Если же требуется транспортировать какое-то сообщение в исключении, как правильно это сделать на практике? Например, как организовать возможность централизованной локализации строк сообщений, загрузку их из ресурсов? S>Особой нужды в локализации исключений нижнего уровня нет. Локализация исключений, проникающих на уровень UI, делается относительно стандартными средствами: конкретный класс исключения оборудуется конструктором с соответствующими параметрами, берет шаблон строки из ресурсов, и компонует сообщение из шаблона и значений своих параметров.
А как тогда анализировать причину сбоя и выводить пользователю инфу, если она приходит с нижнего нелокализованного уровня? Может тогда вообще отказаться от текста и идентифицировать исключения нижнего уровня только по их типу, а соответствующий текст добавлять в верхнем уровне? Или это нарушает инкапсуляцию исключений?
Здравствуйте, Ignoramus, Вы писали:
I>Т.е. в промышленном коде именно так и делают? Оборачивают на каждом уровне?
Да. I>Как именно выглядит это оборачивание — в самом начале каждого публичного метода и конструктора ставится try, а в самом конце catch с пере-throw?
Нет. Не каждого публичного метода. При пересечении границы слоев. Сколько слоев в твоей архитектуре? I>Иначе я не вижу способа обеспечить полный отлов всех исключений в целях их оборачивания. I>При условии присутствия промежуточных оборачивателей — да. Я пытался выяснить можно ли обойтись одним try/catch на верхнем уровне и при этом получать более подробную информацию о сбое. По-видимому это невозможно .
Действительно, практически невозможно. Принципиальным ограничением является отсутствие информации о контексте. Современные управляемые среды уже предоставляют гораздо больше информации, чем это было возможно раньше — в частности, call stack. К сожалению, пока что нет возможности автоматически получить информацию об а) значениях параметров в стеке и б) состоянии объектов. Прежде всего потому, что такая возможность вызвала бы существенное понижение быстродействия "безошибочных" приложений. В принципе, можно ожидать появления подобных возможностей в следующих поколениях управляемых систем. Пока что нам остается следовать приведенным соображениям "вручную". I>Интересно, а где лучше размещать описания классов исключений? Наверное в том же пространстве имен, что и "логический уровень", все классы которого бросают одни и те же исключения? Не выделять в отдельный namespace Exceptions?
Наверное, да. Хотя принципиальной разницы нет — просто удобнее пользоваться, когда для исключений не нужно подключать отдельный namespace.
I>А как тогда анализировать причину сбоя и выводить пользователю инфу, если она приходит с нижнего нелокализованного уровня? Может тогда вообще отказаться от текста и идентифицировать исключения нижнего уровня только по их типу, а соответствующий текст добавлять в верхнем уровне? Или это нарушает инкапсуляцию исключений?
Не нарушает. Информация нижнего уровня все равно читается технически квалифицированными людьми, которые в состоянии понять "File Not Found" независимо от их родного языка.
1.1.4 stable rev. 510
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, Ignoramus, Вы писали:
S>Нет. Не каждого публичного метода. При пересечении границы слоев. Сколько слоев в твоей архитектуре?
Хотел бы я это знать, черт побери! Наверное 3... или 4
Однако же, под "публичными" я имел в виду методы, которые вызываются более верхним слоем (а не просто объявленные как public) С этой поправкой мое утверждение верно?
I>>Иначе я не вижу способа обеспечить полный отлов всех исключений в целях их оборачивания. I>>При условии присутствия промежуточных оборачивателей — да. Я пытался выяснить можно ли обойтись одним try/catch на верхнем уровне и при этом получать более подробную информацию о сбое. По-видимому это невозможно . S>Действительно, практически невозможно. Принципиальным ограничением является отсутствие информации о контексте. Современные управляемые среды уже предоставляют гораздо больше информации, чем это было возможно раньше — в частности, call stack. К сожалению, пока что нет возможности автоматически получить информацию об а) значениях параметров в стеке и б) состоянии объектов. Прежде всего потому, что такая возможность вызвала бы существенное понижение быстродействия "безошибочных" приложений. В принципе, можно ожидать появления подобных возможностей в следующих поколениях управляемых систем. Пока что нам остается следовать приведенным соображениям "вручную".
Как теоретический вариант я рассматривал возможность при получении исключения на верхнем уровне "подсмотреть" в стек, чтобы узнать от какого метода более низкого уровня пришло данное исключение. Если предположить, что каждый "публичный" метод выполняет только одну ф-цию и соответственно переизлучал бы только одно исключение (если бы в нем был оборачиватель), таким образом можно определить причину сбоя, без промежуточных оборачивателей. Бред?
I>>А как тогда анализировать причину сбоя и выводить пользователю инфу, если она приходит с нижнего нелокализованного уровня? Может тогда вообще отказаться от текста и идентифицировать исключения нижнего уровня только по их типу, а соответствующий текст добавлять в верхнем уровне? Или это нарушает инкапсуляцию исключений? S>Не нарушает. Информация нижнего уровня все равно читается технически квалифицированными людьми, которые в состоянии понять "File Not Found" независимо от их родного языка.
Уточню вопрос: использовать ли вообще строки в исключениях нижнего уровня или достаточно их типа, а весь текст обеспечивается верхним уровнем на основании этого типа?
Sinclair wrote:
> Современные управляемые среды уже предоставляют гораздо больше > информации, чем это было возможно раньше — в частности, call stack. К > сожалению, пока что нет возможности автоматически получить информацию > об а) значениях параметров в стеке
Управляемые среды — ацтой
Вообще-то в MS VС++ вполне можно получить stacktrace, значения
аргументов, и даже значения переменных в фреймах функций. Единственное
что нужно — это иметь PDB-файл.
В управляемые среды такое добавить сильно больших сложностей не должно
представить. Вероятно это пока никому не надо, или просто еще не
додумались добавить.
Здравствуйте, Sinclair, Вы писали:
S>К сожалению, пока что нет возможности автоматически получить информацию об а) значениях параметров в стеке и б) состоянии объектов. Прежде всего потому, что такая возможность вызвала бы существенное понижение быстродействия "безошибочных" приложений. В принципе, можно ожидать появления подобных возможностей в следующих поколениях управляемых систем. Пока что нам остается следовать приведенным соображениям "вручную".
Возможность такая, естественно, есть. В каких системах — не трудно догадаться Другое дело, что, для автоматического перезаворачивания исключений, особого толку от состояния объектов и значений параметров я не вижу.
Здравствуйте, Ignoramus, Вы писали:
I>Уточню вопрос: использовать ли вообще строки в исключениях нижнего уровня или достаточно их типа, а весь текст обеспечивается верхним уровнем на основании этого типа?
Использовать. Часто бывает, что сохраненная на самом низком уровне полная информация о причине исключения оказывается очень важной при разборе полетов. Терять такую информацию, если она есть, глупо. В частности, крайне полезным бывает сохранение значения errno.
Не обязательно это могут быть строки. Например, мне иногда приходится порождать исключения при выходе за пределы блока с десериализуемыми данными. Тогда я располагаю информацией о: размере буфера, текущей позиции в буфере и количеством байт, которые хотят прочитать. Для этого в С++ можно использовать, что-то вроде:
class bound_ex_t : public std::exception
{
private :
size_t m_buf_size;
size_t m_pos;
size_t m_required_size;
//! Для того, чтобы можно было сформировать в what().mutable std::string m_what;
public :
bound_ex_t( size_t buf_size, size_t pos, size_t required_size )
: m_buf_size( buf_size ), m_pos( pos ), m_required_size( required_size )
{}
virtual const char * what() const
{
if( m_what.empty() )
{
<создание строки с описанием всей доступной информации>
}
return m_what.c_str();
}
};
bound_ex_t::m_what можно формировать и в конструкторе bound_ex_t, только зачем это делать сразу, если what() у нас могут и не вызвать вообще.
... << RSDN@Home 1.1.4 stable rev. 510>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, eao197, Вы писали:
E>Здравствуйте, Ignoramus, Вы писали:
I>>Уточню вопрос: использовать ли вообще строки в исключениях нижнего уровня или достаточно их типа, а весь текст обеспечивается верхним уровнем на основании этого типа?
E>Использовать. Часто бывает, что сохраненная на самом низком уровне полная информация о причине исключения оказывается очень важной при разборе полетов. Терять такую информацию, если она есть, глупо. В частности, крайне полезным бывает сохранение значения errno.
Кстати о номерах ошибок. Идея конечно заманичвая, но ее основной недостаток, по моему опыту, это необходимость консистентной нумерации ошибок во всем приложении, во всех уровнях архитектуры. Это лишняя связь, и довольно-таки напрягает имхо. Может поэтому в std::exception есть строковый what, а не числовой
Здравствуйте, Sinclair, Вы писали:
S>Действительно, практически невозможно. Принципиальным ограничением является отсутствие информации о контексте. Современные управляемые среды уже предоставляют гораздо больше информации, чем это было возможно раньше — в частности, call stack. К сожалению, пока что нет возможности автоматически получить информацию об а) значениях параметров в стеке и б) состоянии объектов. Прежде всего потому, что такая возможность вызвала бы существенное понижение быстродействия "безошибочных" приложений. В принципе, можно ожидать появления подобных возможностей в следующих поколениях управляемых систем. Пока что нам остается следовать приведенным соображениям "вручную".
Современные управляемые среды всё это умели делать давным давно. Вот смотрите, ниже я привожу пример стека со всеми локальными переменными процедур и полями объектов, причем каждый пункт — это гиперссылка на соответствующую позицию в исходном тексте программы.
Фрагмент:
Сама программа:
MODULE TestException;
IMPORT StdLog, Math;
TYPE
MyObject = RECORD
x, y, z: REAL
END;
PROCEDURE Sqrt (x : REAL): REAL;
BEGIN ASSERT(x >= 0.0, 20);
RETURN Math.Sqrt(x)
END Sqrt;
PROCEDURE Do*;
VAR obj: MyObject;
a, b, c: REAL;
BEGIN
a := 111.0;
b := 222.0;
c := 333.0;
obj.x := 444.0;
obj.y := 555.0;
obj.z := 666.0;
c := Sqrt(-777.0);
StdLog.Real(c)
END Do;
END TestException.
Полная развертка стека (при конвертации в plain text специальные view, естественно, исчезли):
Здравствуйте, Ignoramus, Вы писали:
I>Кстати о номерах ошибок. Идея конечно заманичвая, но ее основной недостаток, по моему опыту, это необходимость консистентной нумерации ошибок во всем приложении, во всех уровнях архитектуры. Это лишняя связь, и довольно-таки напрягает имхо. Может поэтому в std::exception есть строковый what, а не числовой
Я ведь не предлагал вводить собственную систему номеров ошибок, а сохранять, где это имеет смысл, значение errno. А за консистентность нумерации ошибок в errno стандартная (и не только) библиотека отвечает. На Windows так же можно и GetLastError использовать при работе с WinAPI.
... << RSDN@Home 1.1.4 stable rev. 510>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, Cyberax, Вы писали:
C>Вообще-то в MS VС++ вполне можно получить stacktrace, значения C>аргументов, и даже значения переменных в фреймах функций. Единственное C>что нужно — это иметь PDB-файл.
От PDB файла не всегда много толку, если включена агресивная оптимизация и Frame-Pointer Omission.
"For every complex problem, there is a solution that is simple, neat,
and wrong."
Cyberax wrote: > > ASSERT'ы — это НЕ мусор. Это чрезвычайно удобное средство отладки.
Более того, хорошо поставленный assert помогает защитить свой код от
лазанья в него "умелыми ручками" всяких разных других участников проекта
— из того числа, которые могут позвать любую обнаруженную ими функцию в
любом контексте, и не читают комментариев.
Без ассерта это кончится тем, что "что-то твой код глючит". С ассертом
диалог будет примерно следующий: "что-то у тебя ассерт срабатывает" —
"до твоей правки не срабатывал" — "а как тогда мне сделать XXX?". И вот
с этого последнего вопроса можно уже начинать нормальный диалог...
IT wrote: > > C>Или, например, вот такой код (спас часы отладки): > > Так может такие проверки должны быть штатными и использоваться не только > в режиме отладки?
Да, безусловно. Ассерты должны оставаться в релизе. Надо только
придумать, как сделать так, чтобы последние слова программы попали таки
тебе в руки вместе с bag report'ом.
Глеб Алексеев wrote: > > IT>Так может такие проверки должны быть штатными и использоваться не > только в режиме отладки? > Зачем, если они срабатывают только при наличии ошибки в программе (и > теоретически в окончательной версии их быть не должно) и могут снижать > производительность?
Потому, что даже в релизнутой программе могут остаться ошибки. И лучше,
чтобы последние слова упавшей программы были осмысленными, чем просто
слепой GPF.
Cyberax wrote: > > А зачем? assert показывает ошибки программиста, а не пользователя. То > есть ни при каком варианте работы событий пользователь не должен его > получить, а значит и включать его не надо. > > В рельной жизни assert'ы обычно оставляют в бэта-версиях, и выкидывают в > релизах.
А что, в релизах каким-то волшебным образом нет ни одной ощибки?
Какая альтернатива существует у программы, которая вошла в состояние,
когда должен бы сработать assert, а assert-а то и нету? Только сойти с
ума, и в лучшем случае упасть на GPF'е. А в худшем — безнадежно
испортить пользовательские файлы.