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. Логические ошибки