Читаем Программирование. Принципы и практика использования C++ Исправленное издание полностью

Выполните эту программу при разных значениях. Выведите на печать значения переменных area1, area2, area3 и ratio. Вставьте в программу больше проверок разных ошибок. Вы уверены, что перехватите все ошибки? Это вопрос без подвоха; в данном конкретном примере можно ввести правильный аргумент и перехватить все возможные ошибки.

Существует другой способ решить описанную проблему: использовать исключения (exceptions).

<p id="AutBody_Root074"><strong>5.6. Исключения</strong></p>

Как и в большинстве языков программирования, в языке С++ существует механизм обработки ошибок: исключения. Основная идея этого понятия заключается в отделении выявления ошибки (это можно сделать в вызываемой функции) от ее обработки (это можно сделать в вызывающей функции), чтобы гарантировать, что ни одна выявленная ошибка не останется необработанной. Иначе говоря, исключения создают механизм, позволяющий сочетать наилучшие подходы к обработке ошибок, исследованные нами до сих пор. Какой бы легкой ни была обработка ошибок, исключения сделают ее еще легче.

Основная идея заключается в следующем: если функция обнаруживает ошибку, которую не может обработать, она не выполняет оператор return как обычно, а генерирует исключение с помощью оператора throw, показывая, что произошло нечто неправильное.

Любая функция, прямо или косвенно вызывающая данную функцию, может перехватить созданное исключение с помощью оператора catch, т.е. указать, что следует делать, если вызываемый код использовал оператор throw. Функция расставляет ловушки для исключения с помощью блока try (мы опишем его в следующих разделах), перечисляя виды исключений, которые она хочет обработать в своих разделах catch блока try. Если ни одна из вызывающих функций не перехватила исключение, то программа прекращает работу.

Мы еще вернемся к исключениям позже (в главе 19), чтобы использовать их немного более сложным способом.

<p id="AutBody_Root075"><strong>5.6.1. Неправильные аргументы</strong></p>

Рассмотрим вариант функции area, использующий исключения.

class Bad_area { }; // Тип, созданный специально для сообщений

                    // об ошибках,

      // возникших в функции area

      // Вычисляет площадь прямоугольника;

      // при неправильном аргументе генерирует исключение Bad_area

int area(int length, int width)

{

  if (length<=0 || width<=0) throw Bad_area;

  return length*width;

}

Иначе говоря, если аргументы правильные, то программа всегда возвращает площадь прямоугольника, а если нет, то выходим из функции area с помощью оператора throw, надеясь найти ответ в одном из разделов catch. Bad_area — это новый тип, предназначенный исключительно для генерирования исключений в функции area, так, чтобы один из разделов catch распознал его как исключение, сгенерированное функцией area. Типы, определенные пользователями (классы и перечисления), обсуждаются в главе 9. Обозначение Bad_area означает “Создать объект типа Bad_area”, а выражение throw Bad_area означает “Создать объект типа Bad_area и передать его (throw) дальше”.

Теперь функцию можно написать так:

int main

try {

  int x = –1;

  int y = 2;

  int z = 4;

  // ...

  int area1 = area(x,y);

  int area2 = framed_area(1,z);

  int area3 = framed_area(y,z);

  double ratio = area1/area3;

}

catch (Bad_area) {

  cout << "Ой! Неправильный аргумент функции area\n";

}

Во-первых, этот фрагмент программы обрабатывает все вызовы функции area как вызов из модуля main, так и два вызова из функции framed_area. Во-вторых, обработка ошибки четко отделена от ее выявления: функция main ничего не знает о том, какая функция выполнила инструкцию throw Bad_area, а функция area ничего не знает о том, какая функция (если такая существует) должна перехватывать исключения Bad_area, которые она генерирует. Это разделение особенно важно в крупных программах, написанных с помощью многочисленных библиотек. В таких программах ни один человек не может обработать ошибку, просто поместив некоторый код в нужное место, поскольку никто не может модифицировать код одновременно в приложении и во всех библиотеках.

<p id="AutBody_Root076"><strong>5.6.2. Ошибки, связанные с диапазоном</strong></p>

Большинство реальных программ работает с наборами данных. Иначе говоря, они используют разнообразные таблицы, списки и другие структуры данных. В контексте языка С++ наборы данных часто называют контейнерами (containers). Наиболее часто используемым контейнером стандартной библиотеки является тип vector, введенный в разделе 4.6.

Перейти на страницу:
Нет соединения с сервером, попробуйте зайти чуть позже