Написал некоторый класс, который внутри себя полностью "прозрачен" и "безопасен" по отношению к исключениям, т.е. нет утечки ресурсов, кругом RAII и все такое , но catch нигде нет.
И вот дошла разработка до самого верхнего, "интерфейсного" класса, который будет предоставлен пользователю.
Я решил (кстати, может у кого-нибудь есть другие идеи?), что методы класса не должны бросать что попало, а только исключения определенного класса — например MyException. Я предполагаю, что пользователю будет удобнее централизованно ловить один тип исключений, а не копаться в исключениях разных уровней.
(* не использую сторонних библиотек, исключения могут возникнуть только стандартные и мои собственные)
Итак, я определил какие из интересующих меня стандартных исключений должны быть "завернуты" в MyException, какие MyException я сам буду бросать. Все остальные завертываются в UnknownError (: public MyException ).
Таким образом, получается, мне нужно "обернуть" вызов каждого публичного метода этого "юзерского" класса (включая конструктор) в try/catch с последующим перевыбросом MyException.
Вопросы следующие:
1) Набор блоков catch и код (разбор по типам) в них будет одинаковым для каждого публичного метода юзерского класса. Нет ли способа завернуть их все в какую-нибудь функцию или объект, чтобы не писать несколько раз одно и то же?
2) Какие вообще есть недостатки у такой схемы обработки исключений, которые я возмоно не учел?
Здравствуйте, Ignoramus, Вы писали:
I>1) Набор блоков catch и код (разбор по типам) в них будет одинаковым для каждого публичного метода юзерского класса. Нет ли способа завернуть их все в какую-нибудь функцию или объект, чтобы не писать несколько раз одно и то же?
Только недавно обсуждали здесь
Здравствуйте, Ignoramus, Вы писали:
I>Я решил (кстати, может у кого-нибудь есть другие идеи?), что методы класса не должны бросать что попало, а только исключения определенного класса — например MyException. Я предполагаю, что пользователю будет удобнее централизованно ловить один тип исключений, а не копаться в исключениях разных уровней. I>... I>Таким образом, получается, мне нужно "обернуть" вызов каждого публичного метода этого "юзерского" класса (включая конструктор) в try/catch с последующим перевыбросом MyException.
У меня сейчас такая же проблема, только еще куча сторонних библиотек Вовсю использую exception filter но этого все равно не достаточно. Склоняюсь к выводу что исключения С++ не предназначены для таких задач, получается, что для трансляции коды вовзврата и то удобнее, а пока везде понатыканы catch.
Здравствуйте, Ignoramus, Вы писали:
I>Я решил (кстати, может у кого-нибудь есть другие идеи?), что методы класса не должны бросать что попало, а только исключения определенного класса — например MyException. Я предполагаю, что пользователю будет удобнее централизованно ловить один тип исключений, а не копаться в исключениях разных уровней.
I>(* не использую сторонних библиотек, исключения могут возникнуть только стандартные и мои собственные)
I>Итак, я определил какие из интересующих меня стандартных исключений должны быть "завернуты" в MyException, какие MyException я сам буду бросать. Все остальные завертываются в UnknownError (: public MyException ).
Унаследуйся от std::exception, и не придется ничего заворачивать ИМХО
Здравствуйте, MuTPu4, Вы писали:
MTP>Короче, было бы здорово, если бы кто-то подсказал красивое решение, а то тут и до макросов не далеко
Смотрели по ссылке в этом сообщении ? Re: Как реюзать catch-блоки?
Здравствуйте, MuTPu4, Вы писали:
MTP>У меня сейчас такая же проблема, только еще куча сторонних библиотек Вовсю использую exception filter но этого все равно не достаточно. Склоняюсь к выводу что исключения С++ не предназначены для таких задач, получается, что для трансляции коды вовзврата и то удобнее, а пока везде понатыканы catch.
MTP>
MTP>Ну и где же удобство? MTP>Короче, было бы здорово, если бы кто-то подсказал красивое решение, а то тут и до макросов не далеко
>получается, что для трансляции коды вовзврата и то удобнее
то есть писать что то типа
int ret;
.....
ret = can_be_bad () ;
if (ret < 0)
{
// плохая ветка return ret;
}
....
//продолжаем работать
лучше чем регинирить исключения
просто люди считают что, примененяя exception, они решают все свои проблеммы в плане обработки ошибок.
Это не так. Всё равно обработкой ошибок надо заниматься.
Кончено, я же написал что использую. Отличная техника, респект автору. А вообще, я сейчас расставил все эти try-catch для трансляции и не так уж много получилось , это у страха глаза велики.
А>лучше чем регинирить исключения А>просто люди считают что, примененяя exception, они решают все свои проблеммы в плане обработки ошибок. А>Это не так. Всё равно обработкой ошибок надо заниматься.
Это понятно. Собственно, речь идет не о стратегии обработки исключений/ошибок в программе, а всего лишь о трансляции исключений одного типа в другой. Например, как в моем случае, сторонняя библиотека использует свою иерархию исключений, а я — свою и мне не хочется выпускать исключения библиотеки наружу. Поскольку я использую эту библиотеку не в одной/двух функциях, а пишу враппер над ней, то почти в каждом методе моего класса приходится расставлять try-catch, хотя, обрабатывать исключения я не собираюсь. А коды возврата по своей сути предназначены для перехвата и дальнейшей передачи вверх, что иногда удобно. Позволю себе еще разок привести свой пример для нагладности:
//Везде исключения. Самый неудобый вариант, хоть и с exception_filter.
//Если оборачивать так каждый метод/вызов то читаемость очень сильно падает.
//Кстати, интересно насколько это приемлемо с точки зрения эффективности.try {
can_throw( );
}
catch( ... ) {
exception_filter( );
}
//Везде коды возврата. На мой взглад, это смотрится несколько лучше.if( ( ret = can_fail( ) ) == fail )
return( translate_code( ret ) );
//Работает с сишной библиотекой. Наверх отправляем свои исключения.
//Вот хотелось бы такого синтаксиса...
check_ret( can_fail( ) );
Ну да ладно, особой проблемы уменя нет, да и у автора топика, как я понял, тоже. Так что не буду больше никому морочить голову .
Здравствуйте, MuTPu4, Вы писали:
MTP>Ну да ладно, особой проблемы уменя нет, да и у автора топика, как я понял, тоже. Так что не буду больше никому морочить голову .
Нет, почему же, меня этот вопрос тоже интересует, так что можем продолжить тему . Когда-то давно, когда я только познакомился с исключениями как методикой обработки ошибок, я, кстати, тоже поднимал этот вопрос, но так и не получил удовлетворительного ответа. Можно сказать, что в некотором смысле я пока забил на это дело, но проблема осталась
Проблема возникает в коде, который не является "вещью в себе", а имеет некоторый внешний интерфейс к клиентскому коду, т.е. практически всегда . Исключение составляет только контейнеры а ля STL и тому подобный код, который просто "прозрачно" пропускает через себя все исключения (т.е. подразумевает что клиент сам знает что это за исключения и что с ними делать).
Конечной целью любой обработки ошибок является предоставление клиентскому коду достаточной информации в исключении, чтобы он мог выдать сообщение пользователю и/или принять решения о том, что делать дальше.
Проблема заключается в том, что на каждом уровне кода, от нижнего к верхнему, исключения по сути имеют разный тип (даже если формально они имеют один тип), например, не следовало бы смешивать "переполнение буфера" на самом нижнем уровне доступа к файлу и "не удалось открыть документ" на пользовательском уровне.
Т.е. необходимо на каждом уровне отлавливать исключения и "переизлучать" их в другой форме, в обертке данного уровня.
Для этого, как ты правильно заметил, нужно везде ставить обертки try/catch почти во всех классах всех уровнях. Доходит даже до try/catch function-block конструкторов (их единственное применение ).
Так вот, это настолько утомительно и код становится настолько уродским, что я пришел к выводу, что это неоправданно дорогая цена за возможность получить на верхнем уровне информацию вроде "Не удалось сохранить документ потому что диск переполнен". Ограничиваюсь просто "Не удалось сохранить документ" — т.е. единственной затычкой на все исключения в данной функции/команде "Сохранить документ". Максимум — ставлю дискриминаторную затычку на методы только верхнего уровня, вроде описанной в данном топике.
Если кто-то предложит технику для решения данной проблемы, буду только благодарен . Но имхо это скорее архитектурная проблема, свойственная самим исключениям как сущности.
P.S. Проблема "переизлучения", кстати, есть и в методе возврата кода ошибки (как устаревшей альтернативе исключениям), но там ее приходится всегда решать, нельзя обойти .