cerr << "error: " << e.what() << '\n';
keep_window_open();
return 1; // 1 означает сбой
}
catch (...) {
cerr << "Ой: неизвестное исключение !\n";
keep_window_open();
return 2; // 2 означает сбой
}
Здесь, для того чтобы перехватить все исключения, мы добавили инструкцию catch(...).
Когда исключения обоих типов (out_of_range и runtime_error) рассматриваются как разновидности одного и того же типа exception, говорят, что тип exception является базовым типом (супертипом) для них обоих. Этот исключительно полезный и мощный механизм будет описан в главах 13–16.
Снова обращаем ваше внимание на то, что значение, возвращаемое функцией main(), передается системе, вызвавшей программу. Некоторые системы (такие как Unix) часто используют это значения, а другие (такие как Windows), как правило, игнорируют их. Нуль означает, что программа завершилась успешно, а ненулевое значение, возвращенное функцией main(), означает какой-то сбой.
При использовании функции error() для описания возникшей проблемы часто необходимо передать две порции информации. В данном случае эти две порции просто объединяются в одну строку. Этот прием настолько широко распространен, что мы решили представить его в виде второго варианта функции error().
void error(string s1, string s2)
{
throw runtime_error(s1+s2);
}
Этой простой обработки ошибки нам будет достаточно, пока ситуация не усложнится и потребуется придумать более изощренный способ исправить ситуацию.
Обратите внимание на то, что использование функции error() не зависит от количества ее предыдущих вызовов: функция error() всегда находит ближайший раздел catch, предусмотренный для перехвата исключения runtime_error (обычно один из них размещается в функции main()). Примеры использования исключений и функции error() приведены в разделах 7.3. и 7.7. Если исключение осталось неперехваченным, то система выдаст сообщение об ошибке (неперехваченное исключение).
ПОПРОБУЙТЕ
Для того чтобы увидеть неперехваченное исключение, запустите небольшую программу, в которой функция error() не перехватывает никаких исключений.
5.6.4. Суживающие преобразования
В разделе 3.9.2 продемонстрирована ужасная ошибка: когда мы присвоили переменной слишком большое значение, оно было просто усечено. Рассмотрим пример.
int x = 2.9;
char c = 1066;
x будет равно 2, а не 2.9, поскольку переменная x имеет тип int, а такие числа не могут иметь дробных частей. Аналогично, если используется обычный набор символов ASCII, то переменная c будет равна 42 (что соответствует символу *), а не 1066, поскольку переменные типа char не могут принимать такие большие значения.
В разделе 3.9.2 показано, как защититься от такого сужения путем проверки. С помощью исключений (и шаблонов; см. раздел 19.3) можно написать функцию, проверяющую и генерирующую исключение runtime_exception, если присваивание или инициализация может привести к изменению значения. Рассмотрим пример.
int x1 = narrow_cast
int x2 = narrow_cast
char c1 = narrow_cast
char c2 = narrow_cast
Угловые скобки, <...>, означают то же самое, что и в выражении vector. Они используются, когда для выражения идеи возникает необходимость указать тип, а не значение. Аргументы, стоящие в угловых скобках, называют narrow_cast, определенный в заголовочном файле std_lib_facilities.h и реализованный с помощью функции error(). Слово cast[7] означает приведение типа и отражает роль этой операции в ситуации, когда что-то “сломалось” (по аналогии с гипсовой повязкой на сломанной ноге). Обратите внимание на то, что приведение типа не изменяет операнд, а создает новое значение, имеющее тип, указанный в угловых скобках и соответствующий операнду.
5.7. Логические ошибки