Коллеги, хотелось бы поднять тему обработки исключений в С++ приложениях.
При разработке системы отслеживания и обработки ошибок в объектно-ориентированном приложении порою сталкиваешься с дилемой: какой подход и в каком случае применять для решения этих задач. Фактически речь идет о выборе между отлавливанием через try-catch, предпологающим написание классов исключений и обычным анализом возвращаемого статуса выполнения. Кто чем пользуется и в каких случаях пользуется?
Здравствуйте, Slick, Вы писали:
S>Коллеги, хотелось бы поднять тему обработки исключений в С++ приложениях. S>При разработке системы отслеживания и обработки ошибок в объектно-ориентированном приложении порою сталкиваешься с дилемой: какой подход и в каком случае применять для решения этих задач. Фактически речь идет о выборе между отлавливанием через try-catch, предпологающим написание классов исключений и обычным анализом возвращаемого статуса выполнения. Кто чем пользуется и в каких случаях пользуется?
Хотя ву некоторых случаях лучше применять исключения (например в случае очень редкой ошибки или в конструкторе), хочу отметить, что исключение, это разновидность GoTo, это очень шрусный оператор
If the milk turns out to be sour,
I ain't the kind of pussy to drink it
Здравствуйте, Slick, Вы писали:
S>Коллеги, хотелось бы поднять тему обработки исключений в С++ приложениях. S>При разработке системы отслеживания и обработки ошибок в объектно-ориентированном приложении порою сталкиваешься с дилемой: какой подход и в каком случае применять для решения этих задач. Фактически речь идет о выборе между отлавливанием через try-catch, предпологающим написание классов исключений и обычным анализом возвращаемого статуса выполнения. Кто чем пользуется и в каких случаях пользуется?
Сделал класс HResultTest, поведение которого управляется тучей флагов.
Перекрыл ему оператор присваивания, так, что HResultTest::operator=(HRESULT) проверяет входное значение и может вывалить Assertion Fault и/или метнуть исключение.
Дальше с помощью макросов и бениной матери можно делать чудеса.
Здравствуйте, Кодт, Вы писали:
К>Сделал класс HResultTest, поведение которого управляется тучей флагов. К>Перекрыл ему оператор присваивания, так, что HResultTest::operator=(HRESULT) проверяет входное значение и может вывалить Assertion Fault и/или метнуть исключение.
К>Дальше с помощью макросов и бениной матери можно делать чудеса.
Александреску в своей последней статье Enforcements все это сделал очень красиво.
Здравствуйте, MaximE, Вы писали:
ME>Александреску в своей последней статье Enforcements все это сделал очень красиво.
Действительно
Единственный нюанс, который хочется отметить. При работе с COM нужно запоминать и проверять HRESULT,
так что enforcement "по-тупому" выглядит примерно так
— и по части допустимых значений (например, разборщик строки имеет право в реальной жизни вернуть S_OK или E_FAIL, а все остальное будет считаться неприятным сюрпризом),
— и по способу обработки: в одном и том же блоке
— — некоторые ошибки подлежат отладке (к примеру, мы подаем на вход парсера строковый литерал, и ожидаем исключительно S_OK)
— — другие мечут исключения (выделение памяти или создание объекта в родном COM-сервере)
— — третьи обрабатываются или игнорируются (на входе парсера — неизвестная строка)
то приходится либо завести тучу разных SmartHRESULT с разными политиками, либо настраивать политики на месте:
Здравствуйте, Slick, Вы писали:
S>Коллеги, хотелось бы поднять тему обработки исключений в С++ приложениях. S>При разработке системы отслеживания и обработки ошибок в объектно-ориентированном приложении порою сталкиваешься с дилемой: какой подход и в каком случае применять для решения этих задач. Фактически речь идет о выборе между отлавливанием через try-catch, предпологающим написание классов исключений и обычным анализом возвращаемого статуса выполнения. Кто чем пользуется и в каких случаях пользуется?
Обычно получаетчя примерно так:
if (OK==f(x))
if (OK==f2(x))
if (OK==f3(x))
else
else
else
или для красоты:
bool success;
и то же самое без вложенности
когда это вырастает больше, чем на 1/2 страницы, оказывается очень полезным еще вчера подумать про исключения:
try
f(x)
f2(x)
f3(x)
catch
вот такую вот вывел эвристику
мгновенность операции компенсируется бесконечностью цикла
Здравствуйте, Slick, Вы писали:
S>Коллеги, хотелось бы поднять тему обработки исключений в С++ приложениях. S>При разработке системы отслеживания и обработки ошибок в объектно-ориентированном приложении порою сталкиваешься с дилемой: какой подход и в каком случае применять для решения этих задач. Фактически речь идет о выборе между отлавливанием через try-catch, предпологающим написание классов исключений и обычным анализом возвращаемого статуса выполнения. Кто чем пользуется и в каких случаях пользуется?
Я делю ошибки на два вида:
1) те которые я ожидаю
2) и те которые маловероятны
Первые — лучше обрабатывать обычным способом (по возвращаемому результату)
Вторые — эксепшенами.
Например:
Работа с файлами:
Вполне вероятно, что может произойти ошибка при открытии файла и эксепшен лучше не использовать.
Если уж мы его благополучно открыли, то маловероятно что произойдет ошибка при чтении/записи лучше использовать эксепшены.
Для ошибок, которые обнаруживаются отладочным кодом — лучше тоже использовать эксепшены (типа: InternalError).
Здравствуйте, Slick, Вы писали:
S>Коллеги, хотелось бы поднять тему обработки исключений в С++ приложениях. S>При разработке системы отслеживания и обработки ошибок в объектно-ориентированном приложении порою сталкиваешься с дилемой: какой подход и в каком случае применять для решения этих задач. Фактически речь идет о выборе между отлавливанием через try-catch, предпологающим написание классов исключений и обычным анализом возвращаемого статуса выполнения. Кто чем пользуется и в каких случаях пользуется?
Imho исключения весчь исключительно полезная Можно в одном месте централизировать все обработку ошибок, не надо заводить всякие разные коды ошибок и плюс ещё куча всяких рулезов Только нужно юзать Resource Acquisition Is Initialisation (RAII), а то проблемы гарантированы.
Здравствуйте, Slick, Вы писали:
S>Коллеги, хотелось бы поднять тему обработки исключений в С++ приложениях. S>При разработке системы отслеживания и обработки ошибок в объектно-ориентированном приложении порою сталкиваешься с дилемой: какой подход и в каком случае применять для решения этих задач. Фактически речь идет о выборе между отлавливанием через try-catch, предпологающим написание классов исключений и обычным анализом возвращаемого статуса выполнения. Кто чем пользуется и в каких случаях пользуется?
В принципе, исключения и их использование обсуждаются в книге Рихтера (Applied MS .NET Framework Programming), правда для .NET-а , но я думаю подход в C++ и .NET к обработке ошибок похож (хотя в .NEТ исключения быстрее, следовательно их можно более аггресивно использовать.
Здравствуйте, Kuzma K., Вы писали:
KK>когда это вырастает больше, чем на 1/2 страницы, оказывается очень полезным еще вчера подумать про исключения: KK>
KK>try
KK> f(x)
KK> f2(x)
KK> f3(x)
KK>catch
KK>
KK>вот такую вот вывел эвристику
Во первых, вы используете разновидность GoTo, а это очень плохой оператор, а во вторых, вы увеличиваете вероятность падения программы — как известно, два не пойманных исключения = аварийному завершению программы.
Если я забуду обработать одну ошибку в функции, то у меня нарушится логика работы, и вероятно, не будет ни чего плохого, но если я забуду обработать два исключения ...
Так что уж лучше без них.
Правдо те ошибка, что мало вероятны, можно и обработать исключениями
Удалено избыточное цитирование. -- ПК.
If the milk turns out to be sour,
I ain't the kind of pussy to drink it
Здравствуйте, skyline, Вы писали:
S>Здравствуйте, Slick, Вы писали:
S>Хотя ву некоторых случаях лучше применять исключения (например в случае очень редкой ошибки или в конструкторе)
Я считаю, что исключения в конструкторах применять нельзя, нет гарантии, что будет вызван деструктор (он и не должен вызываться, объект с точки зрения логики еще не созался полностью). Если в конструкторе Вы выделили память, а дальте эксепшен, то эта память так и повиснет в воздухе. Даже дядяка СтраусМертв пишет "всю сложную инициализацию в отдельный метод а конструктор и деструктор без исключений нужно делать". Он умный, он знает "когда страус умер"
> Я считаю, что исключения в конструкторах применять нельзя, нет гарантии, что будет вызван деструктор (он и не должен вызываться, объект с точки зрения логики еще не созался полностью). Если в конструкторе Вы выделили память, а дальте эксепшен, то эта память так и повиснет в воздухе.
dtor действительно не вызывается для неполностью сконструированного объекта. А для того, чтобы не вешать память, нужно пользоваться std::auto_ptr.
Здравствуйте, template, Вы писали:
T>Я считаю, что исключения в конструкторах применять нельзя, нет гарантии, что будет вызван деструктор (он и не должен вызываться, объект с точки зрения логики еще не созался полностью). Если в конструкторе Вы выделили память, а дальте эксепшен, то эта память так и повиснет в воздухе. Даже дядяка СтраусМертв пишет "всю сложную инициализацию в отдельный метод а конструктор и деструктор без исключений нужно делать". Он умный, он знает "когда страус умер"
Исключения это вообще единственный надежный способ вернуть ошибку произошедшую в конструкторе (согласно Страуструпу же).
Трудно написать более менее серьезный проект, в котором конструкторы всех обьектов завершаются с успехом в любом случае.
Как обезопасить себя от ликов, Виталий Заболотный уже сказал (std::auto_ptr).
Здравствуйте, skyline, Вы писали:
S>Во первых, вы используете разновидность GoTo, а это очень плохой оператор,
оператор goto считается плохим, когда он применяется в программе на языке высогого уровня, т.к. нарушает программную логику
это совершенно очевидный и давно доказанный факт, я думаю ты с этим спорить не будешь.
снижение читаемости программы, путанница, вероятность ошибки и т.п.
но такой эффект goto имеет именно в языках уровня
в ассемблере, через который эти операторы реализованы это абсолютно нормальный и неизбежный оператор, и его применеие совершенно оправдано
целый ряд операторов языка высого уровня, на уровне ассемблера реализованы через goto — это и for/while и if и try-catch и еще много
но вот они то как раз опасными, и разрушающими логику не являются, т.к. здесь логика выполнения базируется на других критериях нежели в ассемблере
поэтому справедливо упрекать за применения goto а чистом виде а не за применеие операторов, реализованных через goto
следовательно утверждение "поскольку try-catch реализован через goto то try-catch это дерьмо" не выдерживает никакой критики
Здравствуйте, skyline, Вы писали:
S>Во первых, вы используете разновидность GoTo, а это очень плохой оператор,
Причем тут goto? Исключение разматывает стек. S>а во вторых, вы увеличиваете вероятность падения программы — как известно, два не пойманных исключения = аварийному завершению программы.
Поправка одно. Но как я понял ты имееш в виду исли при раскрутки стека исключением деструктор кинул свое то тогда действительно крах. По этому в деструкторах НЕЛЬЗЯ кидать исключения. S>Если я забуду обработать одну ошибку в функции, то у меня нарушится логика работы, и вероятно, не будет ни чего плохого, но если я забуду обработать два исключения ...
Да и проявлятся она будет после дождичка в четверг. Именно такие ошибки труднее всего поймать, а если у тебя рухнула программа то ты покрайней мере будешь знать что она есть. А если это произошло под отладчиком то еще будешь знать где именно. S>Так что уж лучше без них.
Нетуж лучше с ними. S>Правдо те ошибка, что мало вероятны, можно и обработать исключениями
Хотя и злоупотреблять тоже не стоит.
... << RSDN@Home 1.0 beta 6a >>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Здравствуйте, skyline, Вы писали:
S>Если я забуду обработать одну ошибку в функции, то у меня нарушится логика работы, и вероятно, не будет ни чего плохого, но если я забуду обработать два исключения ... S>Так что уж лучше без них.
Интересный подход... Особенно "...не будет ничего плохого..."
Здравствуйте, Slick, Вы писали:
S>Коллеги, хотелось бы поднять тему обработки исключений в С++ приложениях. S>При разработке системы отслеживания и обработки ошибок в объектно-ориентированном приложении порою сталкиваешься с дилемой: какой подход и в каком случае применять для решения этих задач. Фактически речь идет о выборе между отлавливанием через try-catch, предпологающим написание классов исключений и обычным анализом возвращаемого статуса выполнения. Кто чем пользуется и в каких случаях пользуется?
Давайте конкретизируем обсуждаемый вопрос.
Предположим, для построения механизма обработки ошибок, мы взяли за основу модель исключений try-catch.
Обычным подходом в таком случае, является создание собственного класса исключения, инкапсулирующего информацию о возникшем исключении. Экземпляр этого класса создается в точке возникновения исключения, передается в catch-блок и там обрабатывается.
Вопрос вот в чем.
Что если потенциальных исключений в разрабатываемой системе достаточно много?
Ну, например, некий фрагмент логики, при работе которого может возникнуть 30-40 разного рода исключительных ситуаций.
Очевидно, что заводить свой собственный класс для каждой из потенциально возможных исключительных ситуаций — хреновое решение.
Напрашивается некоторое группирование исключений, с заведением класса исключения для каждой группы и отнесение каждого из исключений к той или иной группе.
По какому принципу стоит разбивать исключения на группы. Может быть по степени фатальноси или по подсистемам где оно возникает?
Пожалуй стоит построить иерархтю классов исключений? Какими критериями руководствоваться при решении такой задачи?
Или может быть нужен в корне другой подход?
Здравствуйте, Slick, Вы писали:
S>Коллеги, хотелось бы поднять тему обработки исключений в С++ приложениях. S>При разработке системы отслеживания и обработки ошибок в объектно-ориентированном приложении порою сталкиваешься с S>дилемой: какой подход и в каком случае применять для решения этих задач. Фактически речь идет о выборе между отлавливанием через try-catch, предпологающим написание классов исключений и обычным анализом возвращаемого статуса выполнения. Кто чем пользуется и в каких случаях пользуется?
В документации к Visual C (Exception Handling: Overview) изложен следующий подход (в моей интерпретации ):
а) Если возникшая ситуация отражена в протоколе функции (метода класса), то следует вернуть соответствующий код ошибки. Например — неверный пароль, переданный в функцию аутентификации.
б) Если какая-то ситуация возникает из-за ошибки времени разработки (например — в функцию передан нулевой указатель), т.е. требуется вмешательство программиста, то исключение не подходит, нужно использовать что-то типа ASSERT().
в) Если возникшую ситуацию нельзя отнести к а) или б), т.е. ты знаешь, что такой поворот допустим во время выполнения, но не знаешь, как выйти из сложивщегося положения, используй исключение — может, кто-то наверху знает? Например — при чтении файла с данными обнаруживается несоответствие формату.
Если вдуматься, то все это заложено в самих терминах: код результата, программная ошибка, исключительная ситуация.
Здравствуйте, Slick, Вы писали:
S> По какому принципу стоит разбивать исключения на S> группы. Может быть по степени фатальноси или по подсистемам где оно S> возникает? Пожалуй стоит построить иерархтю классов исключений?
Очень полезно посмотреть на то, как это сделано в стандартной библиотеке.
Posted via RSDN NNTP Server 1.5 beta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Здравствуйте, Павел Кузнецов, Вы писали:
ПК>Здравствуйте, Slick, Вы писали:
S> По какому принципу стоит разбивать исключения на S> группы. Может быть по степени фатальноси или по подсистемам где оно S> возникает? Пожалуй стоит построить иерархтю классов исключений?
ПК>Очень полезно посмотреть на то, как это сделано в стандартной библиотеке.
А потом посмотреть, как Строуструп ругает эту самую иерархию из STL :))
Ну не знаю. Я обычно исключительные ситуации использую.
А>В документации к Visual C (Exception Handling: Overview) изложен следующий подход (в моей интерпретации ):
А>а) Если возникшая ситуация отражена в протоколе функции (метода класса), то следует вернуть соответствующий код ошибки. Например — неверный пароль, переданный в функцию аутентификации.
А>б) Если какая-то ситуация возникает из-за ошибки времени разработки (например — в функцию передан нулевой указатель), т.е. требуется вмешательство программиста, то исключение не подходит, нужно использовать что-то типа ASSERT().
А>в) Если возникшую ситуацию нельзя отнести к а) или б), т.е. ты знаешь, что такой поворот допустим во время выполнения, но не знаешь, как выйти из сложивщегося положения, используй исключение — может, кто-то наверху знает? Например — при чтении файла с данными обнаруживается несоответствие формату.
А>Если вдуматься, то все это заложено в самих терминах: код результата, программная ошибка, исключительная ситуация.
Исключителдьные ситуации также можно описать в описании функции. В любом случае есть гарантия, что ошибка будет замечена. Либо вызывающая функция ожидает данную исключительную ситуацию как возможный вариант исхода (try catch), либо нет — тогда тем более надо бить в колокола. Использовать коды возврата я бы рекомендовал только в случае предупреждающих ошибок. Аналог — warning-и компилятора. Хочешь показывай, хочешь — нет. Хочешь — останавливай компиляцию, хочешь — нет. В случае же ошибок надо обязательно "крикнуть". Гарантировано заметят, а следовательно ты избежишь незамеченных ошибок, а следовательно глюков программ.
Кстати, можно переопределить terminate с тем, чтобы показывать полную информацию о том, что же произошло. Я так обычно и делаю. Результат — если что-то идет не так, я точно знаю что и где.
Здравствуйте, dkon, Вы писали:
D>Здравствуйте, Кодт, Вы писали:
К>>ATLASSERT( SUCCEEDED( hr = pObj->Play( taram param ) ) );
D>кое-где за такое могут и уволить профи должен знать, что случается с ассертом и выражением внутри него в релизе.
Ой-бояй! Это у меня руки быстрее головы сработали.
Конечно, там должен быть VERIFY( .... )
Здравствуйте, menify, Вы писали:
M>Здравствуйте, template, Вы писали:
M>Исключения это вообще единственный надежный способ вернуть ошибку произошедшую в конструкторе (согласно Страуструпу же).
Как вам уже написали, лучше инициализацию проводить не в конструкторе, а в отдельном методе.
If the milk turns out to be sour,
I ain't the kind of pussy to drink it
Здравствуйте, WolfHound, Вы писали:
WH>Здравствуйте, skyline, Вы писали:
S>Во первых, вы используете разновидность GoTo, а это очень плохой оператор, WH>Причем тут goto? Исключение разматывает стек.
Я имею в виду, что
по сути, одно и тоже, а в обоих случаях программа становится плохо читаемой
можно привести подобный пример с циклами, как мне сегодня писали, но циклы не нарушают логику, и являются базовым понятием теории логических схем. Если ты считаешь, что то же вено для выбросов исключений, приведи пример, как это обозначается на логической схеме алгоритма.
S>Если я забуду обработать одну ошибку в функции, то у меня нарушится логика работы, и вероятно, не будет ни чего плохого, но если я забуду обработать два исключения ... WH>Да и проявлятся она будет после дождичка в четверг. Именно такие ошибки труднее всего поймать, а если у тебя рухнула программа то ты покрайней мере будешь знать что она есть. А если это произошло под отладчиком то еще будешь знать где именно.
Я плохо выразил свою мысль. Если у меня в проге редкая ошибка, то в первом случая прога будет падать по крайне мерее не сразу, а по моему опыту, лучше уж, если у клиента программа работает не правильно, чем падает с сообщением Windows
S>Так что уж лучше без них. WH>Нетуж лучше с ними.
Сколько людей, столько и мнений.
If the milk turns out to be sour,
I ain't the kind of pussy to drink it
Здравствуйте, Slick
S>Какими критериями руководствоваться при решении такой задачи? S>Или может быть нужен в корне другой подход?
Если я правильно понял, вы спрашиваете, как групировать исключительные ситуации?
If the milk turns out to be sour,
I ain't the kind of pussy to drink it
Здравствуйте, skyline, Вы писали:
S>Здравствуйте, Slick
S>Какими критериями руководствоваться при решении такой задачи? S>Или может быть нужен в корне другой подход? S>Если я правильно понял, вы спрашиваете, как групировать исключительные ситуации?
Здравствуйте, Slick, Вы писали:
S>Коллеги, хотелось бы поднять тему обработки исключений в С++ приложениях. S>При разработке системы отслеживания и обработки ошибок в объектно-ориентированном приложении порою сталкиваешься с дилемой: какой подход и в каком случае применять для решения этих задач. Фактически речь идет о выборе между отлавливанием через try-catch, предпологающим написание классов исключений и обычным анализом возвращаемого статуса выполнения. Кто чем пользуется и в каких случаях пользуется?
Здравствуйте, Slick, Вы писали:
S>Здравствуйте, skyline, Вы писали:
S>Здравствуйте, Slick
S>Какими критериями руководствоваться при решении такой задачи? S>Или может быть нужен в корне другой подход? S>Если я правильно понял, вы спрашиваете, как групировать исключительные ситуации?
S>Да, именно так.
S>Просто интересно свежее мнение на эту тему.
Моё мнение таково — существуют 4 вида исключительных ситуаций
1 Не критические ситуации
2 Критические ошибки — программу надо срочно сворачивать, дальше работать нет смысла
3 Программисткие ошибки — только на этапе разработки
4 Ошибки какой-то внешней среды
If the milk turns out to be sour,
I ain't the kind of pussy to drink it
Здравствуйте, skyline, Вы писали:
S>Как вам уже написали, лучше инициализацию проводить не в конструкторе, а в отдельном методе.
Чушь. Исключение в конструкторе обычное дело если пишешь на С++, а не на С с классами.
... << RSDN@Home 1.0 beta 6a >>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Здравствуйте, skyline, Вы писали:
S>Я имею в виду, что
Ууу... Как все запущено... Так нормальные люди не пишут.
S>по сути, одно и тоже, а в обоих случаях программа становится плохо читаемой можно привести подобный пример с циклами, как мне сегодня писали, но циклы не нарушают логику, и являются базовым понятием теории логических схем.
А условные переходы значит уже не являются? S>Если ты считаешь, что то же вено для выбросов исключений, приведи пример, как это обозначается на логической схеме алгоритма.
Хм... Когда я их рисовал в последний раз о исключениях еще даже не слышал... Хотя если подумать то в системе с исключениями у каждой подпрограммы будут два выхода один с результатом второй с исключением.
S>Я плохо выразил свою мысль. Если у меня в проге редкая ошибка, то в первом случая прога будет падать по крайне мерее не сразу, а по моему опыту, лучше уж, если у клиента программа работает не правильно, чем падает с сообщением Windows
Плохой у тебя опыт и бедные твои заказчики.
S>Сколько людей, столько и мнений.
В моей программе перехватываются все исключения(просто надо немного заботися о проектировании). Болие того для выброса исключений я использую пару трюков вобщем лог с исключениями содержит очень подробную информацию о том что (имя исключения), где (фаил, строка), почему(проваленое условие) и коментарии(часть контекста по усмотрению программиста). А если учесть что формат лога строго стандартизирован то для него можно написать смотрелку(что я и сделал).
... << RSDN@Home 1.0 beta 6a >>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Здравствуйте, ssm, Вы писали:
ssm>Здравствуйте, Дмитрий Наумов, Вы писали:
ДН>>Как написал WolfHound, лучше всего ловить через ссылку:
ssm>А почему не константную?
As you wish... А если ты поймал исключение, добавил туда еще какой нить информации и rethrow сделал?
Здравствуйте, Дмитрий Наумов, Вы писали:
ssm>А почему не константную?
ДН>As you wish... А если ты поймал исключение, добавил туда еще какой нить информации и rethrow сделал?
struct E{int i; E(const E &){...}};
void low_level(){
...
try{...}
catch(E &e){
...
e.i++;
raise e;//тоесть тут не произойдет копирование E?
...
}
...
}
void high_level{
try{
...
low_level();
...
}
catch(const E &e){
...
}
}
Здравствуйте, Alexey Chen, Вы писали:
AC>Но это, как и приведенный пример, уже из области C и ембеддед систем в которых C++ не держит исключений. AC>В EVC, например , их просто нет.
Почему нет? Есть. А если указать ключ /EHsc, то даже будет включена "unwind semantics". (EVC 4.0)
Здравствуйте, Дмитро, Вы писали:
Д>Здравствуйте, Alexey Chen, Вы писали:
AC>Но это, как и приведенный пример, уже из области C и ембеддед систем в которых C++ не держит исключений. AC>В EVC, например , их просто нет.
Д>Почему нет? Есть. А если указать ключ /EHsc, то даже будет включена "unwind semantics". (EVC 4.0)
Д>-- Д>Дмитрий
А оно не под CE.NET компилять умеет? Без хитрых приседаний. Это во-первых.
А во-вторых, зачем за новые баги, бабло M$ платить если у меня есть EVC 3.0 и его баги я знаю ?
Да и вопрос был не в этом. Есть некоторые ембеддед платформы для которых для меня доступен только gcc у которого не потрудились при портировании приделать исключения. Просто руководствуясь здравым смыслом, перед тем как писать утильный код который много где используеьтся и не зависит от платформы , стоит подумать, а действительно ли нужны эти исключения.
Здравствуйте, skyline, Вы писали:
S>Здравствуйте, Slick, Вы писали:
S>Здравствуйте, skyline, Вы писали:
S>Здравствуйте, Slick
S>Какими критериями руководствоваться при решении такой задачи? S>Или может быть нужен в корне другой подход? S>Если я правильно понял, вы спрашиваете, как групировать исключительные ситуации?
S>Да, именно так.
S>Просто интересно свежее мнение на эту тему.
S>Моё мнение таково — существуют 4 вида исключительных ситуаций S>1 Не критические ситуации S>2 Критические ошибки — программу надо срочно сворачивать, дальше работать нет смысла S>3 Программисткие ошибки — только на этапе разработки S>4 Ошибки какой-то внешней среды
Одна и та же ситуация может быть критической ошибкой, а может быть ничего не значащей фигней.
Посему как тут строить иерархию исключений, не очень понятно.
Здравствуйте, Коваленко Дмитрий, Вы писали:
КД>Это зависит от компилятора. На BCB5, если меня не подводили глаза — объект копируется. КД>Короче, всякое бывает
Что то мне казалось, что такие вещи регламентируются стандартом... Но во-первых утверждать не буду, во вторых Борланд волен делать что угодно...
S>Или может быть нужен в корне другой подход?
Общий смысл — ловишь базовый класс всех исключений, а потом через dynamic_cast анализируешь — что поймал.
У меня количество catch-ей сократилось как минимум в два раза
Вторым премуществом оказалось то, что все перехваченные исключения анализируются централизовано, поэтому добавлять новые категории исключений достаточно просто. Для COM объектов это оказалось — сам то
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Здравствуйте, Дмитрий Наумов, Вы писали:
ДН>Что то мне казалось, что такие вещи регламентируются стандартом... Но во-первых утверждать не буду, во вторых Борланд волен делать что угодно...
Это вопрос оптимизации... Так же, как возвращение объекта из функции.
Здравствуйте, Кодт, Вы писали:
К>Здравствуйте, Дмитрий Наумов, Вы писали:
ДН>>Что то мне казалось, что такие вещи регламентируются стандартом... Но во-первых утверждать не буду, во вторых Борланд волен делать что угодно...
К>Это вопрос оптимизации... Так же, как возвращение объекта из функции.
А Bell в соседнем посте утверждает обратное... Сам я стандарт по этому пункту не изучал, но в Мейерсе вроде упоминалось отсутствие копирования, хотя может и глючит. А если копирование есть то:
try
{
try
{
// ...
CMyException e;
e.set(1);
throw e;
}
catch(CMyException e1)
{
e1.set(2);
throw;
}
}
catch(CMyException& e2)
{
// что здесь будет в e2 - 1 или 2 ?
}
Здравствуйте, Кодт, Вы писали:
К>Это вопрос оптимизации... Так же, как возвращение объекта из функции.
Нет, это не так:
15.1/4
...
The temporary persists as long as there is a handler being executed for that
exception. In particular, if a handler exits by executing a throw; statement,
that passes control to another handler for the same exception, so the temporary remains.
...
В пред. посте я имел ввиду, что если все же там есть копирование, или еще хуже это отдается на откуп компилятору, то там будет неоднозначность поведения.
Здравствуйте, Bell, Вы писали:
B>Здравствуйте, Коваленко Дмитрий, Вы писали:
КД>Это зависит от компилятора. На BCB5, если меня не подводили глаза — объект копируется. КД>Короче, всякое бывает
B>Вообще-то это жестко оговорено в стандарте (15.1/4) — никаких копирований при throw;
Стандарт, стандарт... пишем же на реализациях
А что говорит стандарт относительно
catch(const exception& exc)
{
throw exc;
}
???
BCB5 не в состоянии распознать исходный тип исключения и швыряет тот, который перехватил — exception
Из-за этой хрени я начал подумывать — а почему в std::exception нет виртуального метода raise
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Здравствуйте, Коваленко Дмитрий, Вы писали:
КД>Здравствуйте, Bell, Вы писали:
B>>Здравствуйте, Коваленко Дмитрий, Вы писали:
КД> КД>>Это зависит от компилятора. На BCB5, если меня не подводили глаза — объект копируется. КД>>Короче, всякое бывает
B>>Вообще-то это жестко оговорено в стандарте (15.1/4) — никаких копирований при throw; КД>Стандарт, стандарт... пишем же на реализациях КД>А что говорит стандарт относительно КД>
КД>??? КД>BCB5 не в состоянии распознать исходный тип исключения и швыряет тот, который перехватил — exception КД>Из-за этой хрени я начал подумывать — а почему в std::exception нет виртуального метода raise
Если вы не хотите чтобы происходило "обрезание" то вместо throw exc используйте throw что по смыслу и является "rethrow catched exception"
Здравствуйте, Коваленко Дмитрий, Вы писали:
КД>Стандарт, стандарт... пишем же на реализациях
Это не освобождает от ответственности писАть правильно (если конечно реализпция это позволяет )
А в данном случае — позволяет. КД>А что говорит стандарт относительно КД>
КД>??? КД>BCB5 не в состоянии распознать исходный тип исключения и швыряет тот, который перехватил — exception КД>Из-за этой хрени я начал подумывать — а почему в std::exception нет виртуального метода raise
В данном случае поведение компилятора абсолютно верно:
15.1/3
A throw-expression initializes a temporary object, the type of which is determined by removing
any toplevel cvqualifiers from the static type of the operand of throw...
Здравствуйте, Bell, Вы писали:
КД>> Это зависит от компилятора. На BCB5, если меня не подводили глаза - КД>> объект копируется. Короче, всякое бывает
B> Вообще-то это жестко оговорено в стандарте (15.1/4) — никаких B> копирований при throw;
Ты что-то путаешь. Напротив, в 15.1/3-5 достаточно ясно говорится, что семантика
throw копирующая. В некоторых случаях компилятор может избегать копирования,
но уж никак не обязан это делать.
Posted via RSDN NNTP Server 1.5 beta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Здравствуйте, Павел Кузнецов, Вы писали:
B>> Вообще-то это жестко оговорено в стандарте (15.1/4) — никаких B>> копирований при throw;
ПК> Ты что-то путаешь. Напротив, в 15.1/3-5 достаточно ясно говорится, ПК> что семантика throw копирующая. В некоторых случаях компилятор ПК> может избегать копирования, но уж никак не обязан это делать.
Прошу прощения, не обратил внимание, что речь идет о перевозбуждении
исключения (throw без "аргументов"). В этом случае поведение описано
в пункте 15.1/6, действительно, никакого копирования быть не должно.
Posted via RSDN NNTP Server 1.5 beta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Здравствуйте, Павел Кузнецов, Вы писали:
ПК>Ты что-то путаешь. Напротив, в 15.1/3-5 достаточно ясно говорится, что семантика ПК>throw копирующая. В некоторых случаях компилятор может избегать копирования, ПК>но уж никак не обязан это делать.
Давай разбираться
15.1/4
The memory for the temporary copy of the exception being thrown is allocated in an unspecified way,
except as noted in 3.7.3.1. The temporary persists as long as there is a handler being executed for that
exception. In particular, if a handler exits by executing a throw; statement, that passes control
to another handler for the same exception, so the temporary remains. When the last handler
being executed for the exception exits by any means other than throw; the temporary object is
destroyed and the implementation may deallocate the memory for the temporary object;
any such deallocation is done in an unspecified way.
The destruction occurs immediately after the destruction of the object declared in the exceptiondeclaration
in the handler.
Это разве не указание компилятору перевыбросить тот же самый объект?
Я предлагаю критерии разделения ошибок, и я уже несколько лет таким критерием пользуюсь им доволен.
J>Одна и та же ситуация может быть критической ошибкой, а может быть ничего не значащей фигней. J>Посему как тут строить иерархию исключений, не очень понятно.
По моему мнению, ты должен сам решить, эта данная ситуация фигня или критическая ошибка.
И вообще, что эт за ситуация ?
If the milk turns out to be sour,
I ain't the kind of pussy to drink it
Здравствуйте, WolfHound, Вы писали:
WH>Здравствуйте, skyline, Вы писали:
S>Я имею в виду, что WH>Ууу... Как все запущено... Так нормальные люди не пишут.
Как именно?
WH>А условные переходы значит уже не являются?
Условные переходы являются, но считаются неудачным решением.
WH>Хм... Когда я их рисовал в последний раз о исключениях еще даже не слышал... Хотя если подумать то в системе с исключениями у каждой подпрограммы будут два выхода один с результатом второй с исключением.
Я читал у многих автором по С (если мне не изменяет память, то и у Мертвого Страуса) что над рабочем месчом Сишника должны висеть диаграммы классов, взаимосвязей между ними и алгоритмов работы. А во вторых, порядочному программисту рекомендуется знать UML. Так что, зря ты не рисуешь диаграммы.
Если ты мне не веришь, то после праздников я тебе сошлюсь на эти книги — просто они у меня на работе.
WH>Плохой у тебя опыт и бедные твои заказчики.
Надо предусмотреть все худшие случаи. А ошибок нет только в "Hello World"
S>Сколько людей, столько и мнений. WH>В моей программе перехватываются все исключения(просто надо немного заботися о проектировании). Болие того для выброса исключений я использую пару трюков вобщем лог с исключениями содержит очень подробную информацию о том что (имя исключения), где (фаил, строка), почему(проваленое условие) и коментарии(часть контекста по усмотрению программиста). А если учесть что формат лога строго стандартизирован то для него можно написать смотрелку(что я и сделал).
Вполне реально это сделать и без использования исключений.
Ты все таки не опроверг моиит приткнзии к исключениям
1 Нарушается логика работы программы
2 Увеличивается вероятность падения.
If the milk turns out to be sour,
I ain't the kind of pussy to drink it
Здравствуйте, WolfHound
S>Как вам уже написали, лучше инициализацию проводить не в конструкторе, а в отдельном методе. WH>Чушь. Исключение в конструкторе обычное дело если пишешь на С++, а не на С с классами.
Существуют два стиля программирования, оба стиля достаточно популярны, и в данной теме спор, какой лучше.
Называть один из стилей чушью — мягко говоря не умно.
Да и вообюще, ни в конструкторах MFC, ни в stl не густо с исключениями
If the milk turns out to be sour,
I ain't the kind of pussy to drink it
Здравствуйте, skyline, Вы писали:
S>Здравствуйте, WolfHound
S>>Как вам уже написали, лучше инициализацию проводить не в конструкторе, а в отдельном методе. WH>>Чушь. Исключение в конструкторе обычное дело если пишешь на С++, а не на С с классами. S>Существуют два стиля программирования, оба стиля достаточно популярны, и в данной теме спор, какой лучше. S>Называть один из стилей чушью — мягко говоря не умно. S>Да и вообюще, ни в конструкторах MFC, ни в stl не густо с исключениями
MFC является примером как не надо программировать.
STL — библиотека контейнеров и алгоритмов. 99% случаев, почему может произойти исключение в STL контейнерах/алгоритмах — конструкторы/ф-ции члены/деструктор пользовательских элементов/функторов могут бросить исключении, или new бросит std::bad_alloc. Потоки в расчет не берем.
Здравствуйте, skyline, Вы писали:
S>Здравствуйте, MaximE
S>А какие известные библиотеки постоянно используют исключения (особенно в конструкторе)?
Врапперы, генерируемые #import так делают.
Многие библиотеки написаны в т.н. "мягком стиле" (особенно MS) — сначала создаем объект, потом его инициализируем с результатом инициализации в виде возвращаемого значения. Видимо, это связано с тем, что создатели библиотеки не хотели бы навязывать пользователю метод обработки ошибок.
Но, лично мне, не по душе двойная инициализация (хотя иногда без нее сложно обойтись, например, при рекурсивной десериализации объектов, содержащих произвольное количество коллекций объектов). Для классов, реализующих идиому "resource acquisition is initialization" такой подход вообще непримлим (MS думает иначе).
BTW, я тут и на www.privet.com слышал, что в MS не пользуют stl. Я так и не смог найти разумного объяснения этому. Моя версия — они знают, какое глючево stl от Dinkum, которую они поставляют со своими компиляторами .
Здравствуйте, skyline, Вы писали:
S>Я плохо выразил свою мысль. Если у меня в проге редкая ошибка, то в первом случая прога будет падать по крайне мерее не сразу, а по моему опыту, лучше уж, если у клиента программа работает не правильно, чем падает с сообщением Windows
Хотел бы ты, чтобы тот, кто пишет программу, которой пользуется ваша бухгалтерия для расчета зарплаты, так же думал?
Здравствуйте, skyline, Вы писали:
S>Условные переходы являются, но считаются неудачным решением.
Довольно часто их применение вполне оправдано и удачно. А необдуманное применение любой возможности языка будет неудачным решением.
S>Я читал у многих автором по С (если мне не изменяет память, то и у Мертвого Страуса) что над рабочем месчом Сишника должны висеть диаграммы классов, взаимосвязей между ними и алгоритмов работы. А во вторых, порядочному программисту рекомендуется знать UML. Так что, зря ты не рисуешь диаграммы.
Не стоит намеренно коверкать фамилию Страуструпа.
С каких пор Страуструп — "автор по С"?
Как Сишник связан с диаграммами классов и т.д.?
Не стоит рисовать диаграммы только ради рисования. Это — средство, а не цель.
WH>>Плохой у тебя опыт и бедные твои заказчики. S>Надо предусмотреть все худшие случаи. А ошибок нет только в "Hello World"
"Предусмотреть" и попрятать все потенциальные ошибки под ковер? Нет уж, лучше вовремя узнать и быстро исправить ошибку, чем через год-два пытаться найти неуловимое расхождение в логике работы программы. Правильнее будет заложить отладочные возможности и отловить как можно больше ошибок на этапе тестирования.
WH>>В моей программе перехватываются все исключения(просто надо немного заботися о проектировании). Болие того для выброса исключений я использую пару трюков вобщем лог с исключениями содержит очень подробную информацию о том что (имя исключения), где (фаил, строка), почему(проваленое условие) и коментарии(часть контекста по усмотрению программиста). А если учесть что формат лога строго стандартизирован то для него можно написать смотрелку(что я и сделал). S>Вполне реально это сделать и без использования исключений.
Можно и на асме все написать... Вот только это не всегда рационально. С исключениями можно сделать так (и обычно делается), что выдача сообщения об ошибке (а также запись в лог и т.д.) будет происходить автоматически, при выбросе исключения. При этом исключается возможность пропустить ошибку незамеченной. И все это при минимуме дополнительных действий.
S>1 Нарушается логика работы программы
Серьезная ошибка — это уже нарушение логики работы программы. А небольшие ошибки, не нарушающие логики программы и которые могут быть исправлены локальными средствами, не нужно выделять исключениями.
S>2 Увеличивается вероятность падения.
Здравствуйте, Дмитрий Наумов, Вы писали:
S>>Если я забуду обработать одну ошибку в функции, то у меня нарушится логика работы, и вероятно, не будет ни чего плохого, но если я забуду обработать два исключения ... ДН>Интересный подход... Особенно "...не будет ничего плохого..."
Да уж...
Жаль, что undefined behaviour не является безусловным форматированием винчестера
Здравствуйте, Slick, Вы писали:
S>>Если я правильно понял, вы спрашиваете, как групировать исключительные ситуации? S>Да, именно так.
Если есть необходимость отлавливать "любое исключение из некоторой группы", то их стоит сгруппировать. Тогда их можно ловить через общий базовый класс и не дублировать обработчики.
Здравствуйте, MaximE, Вы писали:
ME>BTW, я тут и на www.privet.com слышал, что в MS не пользуют stl. Я так и не смог найти разумного объяснения этому. Моя версия — они знают, какое глючево stl от Dinkum, которую они поставляют со своими компиляторами .
А чего ж они не поставляют stlport? Связались с платной кривой Dinkumware... Непонятненько.
Видать, у Динки есть лапа в MS.
(=^.^=) Neko ... << RSDN@Home 1.0 beta 6a >>
Перекуём баги на фичи!
Re[11]: подходы к обработке исключений
От:
Аноним
Дата:
12.05.03 09:56
Оценка:
Здравствуйте, Кодт, Вы писали:
К>Видать, у Динки есть лапа в MS.
Здравствуйте, skyline, Вы писали:
S>Здравствуйте, jazzer
S>Я предлагаю критерии разделения ошибок, и я уже несколько лет таким критерием пользуюсь им доволен.
J>Одна и та же ситуация может быть критической ошибкой, а может быть ничего не значащей фигней. J>Посему как тут строить иерархию исключений, не очень понятно. S>По моему мнению, ты должен сам решить, эта данная ситуация фигня или критическая ошибка. S>И вообще, что эт за ситуация ?
Твои критерии — это основа для создания иерархии классов исключений?
Если да, то одно и то же исключение в разных ситауциях может относиться к различным классам.
Например, не удалось открыть файл: если это стряслось при сохранении документа — это критическая ошибка, а если про открытии файла для лога — ну и хрен с ним. Но кидать-то мы должны нечто конкретное, не зависящее от данной ситуации...