|
Программирование >> Оптимизация возвращаемого значения
class runtime error: public exception{ . . . } class Validat ion error: public runtime error { public: virtual const char * what i void someFunction () { об операторе throw{) / / в конце объявления) . / / Также из стандартной иерархии исключений языка С++ . Этот класс добавлен пользователем. throw{); / / Это переопределение функции, / / объявленной выше в исключении класса. Может генерировать / / подтверждающее исключение. if (проверка правильное тине прошла) { throwvalidation error () ; voiddoSomething() { try{ someFunction() ; { cerr << ex.what () Может генерировать подтверждающее исключение. Вызываетисключение::what(; и никогда Validation error::what(). Вызываемая версия оператора what принадлежит к базовому классу, даже если генерируемое исключение относится к типу Validation error и если Validation error переопределяет виртуальную функцию. Уверен, что подобное расщепляющее поведение никогда не удовлетворит вас. Таким образом, остается перехват исключения по ссылке, который не вызывает ни одной из выше обсуждавшихся проблем. В отличие от перехвата по указателю, вопрос удаления объекта теряет здесь свою актуальность, и поэтому при перехвате исключений стандартного типа не возникает никаких трудностей. От перехвата по значению перехват по ссылке отличается тем, что не вызывает потери данных, а объекты исключения копируются только один раз. Если переписать последний пример, используя перехват по ссылке, то он примет следующий вид: void someFunction() { / / В этой функции ничего не меняется. if (проверка правильности не прошла) { throwValidation error() ; voiddoSomething() { try{ someFunction () ; Здесь без изменений. catch(exceptions ex) { Здесь происходит / / перехват по ссылке вместо / / перехвата по значению. cerr ех.what() ; Теперь вызывает Validation error::what(), а не exception:: what О . При этом в точке throw ничего не меняется. Единственная перемена, которая происходит в операторе catch, состоит в добавлении амперсанда (&). Тем не менее, столь незначительная модификация программы приводит к довольно значительным различиям, так как виртуальные функции в блоке catch теперь работают вполне предсказуемо: функции в Validation error активизируются в случае их переопределения в exception. Какое счастливое совпадение! При перехвате по ссылке вы обходите стороной вопросы удаления объектов, которые в любом случае повлекут за собой проблемы; вы также избегаете потери данных в объектах исключения и сохраняете возможность перехвата стандартных исключений; кроме того, вы ограничиваете количество необходимых копий объектов исгслючения. Согласитесь, это убедительные аргументы, чтобы всегда перехватывать исключения по ссылке! Правило 14. Разумно используйте спецификации исключений Нет смысла отрицать, что определения исключений нравятся всем. Они делают программу более понятной, потому что четко определяют, какие исгслючения может генерировать функция. Иногда компиляторы обнаруживают противоречивые определения исключений во время компиляции. Более того, если функция генерирует исключение, которое отсутствует в ее спецификации исключений, ошибка выявляется во время работы программы, и автоматически вызывается специальная функция unexpected. Таким образом, определение исключений кажется достаточно привлекательным не только для документирования программы, но и для задания ограничений при использовании исключений. Но красота и привлекательность обычно обманчивы. Заданное по умолчанию поведение функции unexpected заключается в вызове функции terminate, и по умолчанию функция terminate вызывает функцию abort. Следовательно, по Подобная гибкость играет существенную роль в случае, если необходимо интегрировать новый код, в котором есть спецификация исключений, с устаревшим, не имеющим ее. Очень важно составлять программное обеспечение таким образом, чтобы минимизировать несогласованность. Во-первых, потому что компиляторы не будут препятствовать вызову функций, спецификации исключений в которых не согласованы со спецификациями исключений в процедурах, содержащих вызовы. Вторая причина кроется в том, что такие вызовы могут остановить выполнение вашей программы. Для начала попробуйте не вводить спецификации исключений в шаблоны, содержащие параметры типов. Рассмотрим шаблон, который на первый взгляд не может генерировать никаких исключений: Плохо разработанный шаблон без спецификаций исключений. template<class Т> умолчанию при возникновении исключения, не входящего в спецификацию, работа программы останавливается. Однако локальные переменные в стековых фреймах функции уничтожены не будут, так как функция abort завершает выполнение профам-мы без проведения очистки. Следовательно, нарушение спецификации исключений можно отнести к разряду катаклизмов, которые лучше никогда не допускать. К сожалению, допустить ошибку, по невнимательности или незнанию написав функции, из-за которых происходит эта ужасная вещь, не составляет особого труда. Компилирующие программы проверяют использование исключений на согласованность со спецификациями исключений только частично. И самое печальное - стандарт языка не предусматривает (хотя компиляторы и могут вывести предупреждение) проверки на вызов функции, которая могла бы нарушить спецификацию исключений в вызывающей функции. Рассмотрим объявление функции f 1, не обладающей спецификацией исключений. Такая функция может генерировать любые исключения: extern void fl {) Может генерировать все что угодно. Теперь рассмотрим функцию f 2, спецификация исключений которой определяет, что она может вызывать исключения только типа int: voidf2 {) throw(int) ; В языке С++ функция f 1 может вызывать функцию f 2, даже если функция f 1 способна генерировать исключение, которое нарушает спецификацию исключений функции f2: voidf2() throw(int) { f 1 {) ; / / Допустимо, даже если f 1 могла бы генерировать что-либо,кроме int.
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |