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

  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() не перехватывает никаких исключений.

<p id="AutBody_Root078"><strong>5.6.4. Суживающие преобразования</strong></p>

В разделе 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(2.9);    // генерирует исключение

int x2 = narrow_cast(2.0);    // OK

char c1 = narrow_cast(1066); // генерирует исключение

char c2 = narrow_cast(85);   // OK

Угловые скобки, <...>, означают то же самое, что и в выражении vector. Они используются, когда для выражения идеи возникает необходимость указать тип, а не значение. Аргументы, стоящие в угловых скобках, называют шаблонными (template arguments). Если необходимо преобразовать значение и мы не уверены, что оно поместится, то можно использовать тип narrow_cast, определенный в заголовочном файле std_lib_facilities.h и реализованный с помощью функции error(). Слово cast[7] означает приведение типа и отражает роль этой операции в ситуации, когда что-то “сломалось” (по аналогии с гипсовой повязкой на сломанной ноге). Обратите внимание на то, что приведение типа не изменяет операнд, а создает новое значение, имеющее тип, указанный в угловых скобках и соответствующий операнду.

<p id="AutBody_Root079"><strong>5.7. Логические ошибки</strong></p>
Перейти на страницу:

Похожие книги

Programming with POSIX® Threads
Programming with POSIX® Threads

With this practical book, you will attain a solid understanding of threads and will discover how to put this powerful mode of programming to work in real-world applications. The primary advantage of threaded programming is that it enables your applications to accomplish more than one task at the same time by using the number-crunching power of multiprocessor parallelism and by automatically exploiting I/O concurrency in your code, even on a single processor machine. The result: applications that are faster, more responsive to users, and often easier to maintain. Threaded programming is particularly well suited to network programming where it helps alleviate the bottleneck of slow network I/O. This book offers an in-depth description of the IEEE operating system interface standard, POSIX (Portable Operating System Interface) threads, commonly called Pthreads. Written for experienced C programmers, but assuming no previous knowledge of threads, the book explains basic concepts such as asynchronous programming, the lifecycle of a thread, and synchronization. You then move to more advanced topics such as attributes objects, thread-specific data, and realtime scheduling. An entire chapter is devoted to "real code," with a look at barriers, read/write locks, the work queue manager, and how to utilize existing libraries. In addition, the book tackles one of the thorniest problems faced by thread programmers-debugging-with valuable suggestions on how to avoid code errors and performance problems from the outset. Numerous annotated examples are used to illustrate real-world concepts. A Pthreads mini-reference and a look at future standardization are also included.

David Butenhof

Программирование, программы, базы данных