Программирование >>  Поддержка объектно-ориентированного программирования 

1 ... 71 72 73 [ 74 ] 75 76 77 ... 120


8.9 Упражнения

I . (*2) Определите семейство списков с двойной связью, которые будут двойниками списков с одной

связью, определенных в $$8.3.

2. (*3) Определите шаблон типа String, параметром которого является тип символа. Покажите как его можно использовать не только для обычных символов, но и для гипотетического класса lchar, который представляет символы не из английского алфавита или расширенный набор символов. Нужно постараться так определить String, чтобы пользователь не заметил ухудшения характеристик программы по памяти и времени или в удобстве по сравнению с обычным строковым классом.

3. (*1 .5) Определите класс Record (запись) с двумя членами-данными: count (количество) и price (цена). Упорядочите вектор из таких записей по каждому из членов. При этом нельзя изменять функцию сортировки и шаблон Vector.

4. (*2) Завершите определения шаблонного класса Map, написав недостающие функции-члены.

5. (*2) Задайте другую реализацию Map из $$8.8, используя списочный класс с двойной связью.

6. (*2.5) Задайте другую реализацию Map из $$8.8, используя сбалансированное дерево. Такие деревья описаны в $$6.2.3 книги Д. Кнут Искусство программирования для ЭВМ т.1, Мир , 1978 [К].

7. (*2) Сравните качество двух реализаций Map. В первой используется класс Link со своей собственной функцией размещения, а во второй - без нее.

8. (*3) Сравните производительность программы подсчета слов из $$8.8 и такой же программы, не использующей класса Map. Операции ввода-вывода должны одинаково использоваться в обеих программах. Сравните несколько таких программ, использующих разные варианты класса Map, в том числе и класс из вашей библиотеки, если он там есть.

9. (*2.5) С помощью класса Map реализуйте топологическую сортировку. Она описана в [К] т.1 , стр. 323-332. (см. упражнение 6).

10. (*2) Модифицируйте программу из $$8.8 так, чтобы она работала правильно для длинных имен и для имен, содержащих пробелы (например, thumb back ).

II . (*2) Определите шаблон типа для чтения различных видов строк, например, таких (предмет,

количество, цена).

1 2. (*2) Определите класс Sort из $$8.4.5, использующий сортировку по методу Шелла. Покажите как можно задать метод сортировки с помощью параметра шаблона. Алгоритм сортировки описан в [К] т.3, $$5.2.1 (см. упражнение 6).

1 3. (*1 ) Измените определения Map и Mapiter так, чтобы постфиксные операции ++ и -- возвращали объект Mapiter.

1 4. (*1 .5) Используйте шаблоны типа в стиле модульного программирования, как это было показано в $$8.4.5 и напишите функцию сортировки, рассчитанную сразу на Vector<T> и Т[].

cout << p.keyO << \t << val << \n;

cout << --------------------\n ;

cout << total\t << total << \n;



ГЛАВА 9.

Я прервал вас, поэтому не прерывайте меня.

- Уинстон Черчилл

В этой главе описан механизм обработки особых ситуаций и некоторые, основывающиеся на нем, способы обработки ошибок. Механизм состоит в запуске особой ситуации, которую должен перехватить специальный обработчик. Описываются правила перехвата особых ситуаций и правила реакции на неперехваченные и неожиданные особые ситуации. Целые группы особых ситуаций можно определить как производные классы. Описывается способ, использующий деструкторы и обработку особых ситуаций, который обеспечивает надежное и скрытое от пользователя управление ресурсами.

9.1 Обработка ошибок

Создатель библиотеки способен обнаружить динамические ошибки, но не представляет какой в общем случае должна быть реакция на них. Пользователь библиотеки способен написать реакцию на такие ошибки, но не в силах их обнаружить. Если бы он мог, то сам разобрался бы с ошибками в своей программе, и их не пришлось бы выявлять в библиотечных функциях. Для решения этой проблемы в язык введено понятие особой ситуации.

Только недавно комитетом по стандартизации С++ особые ситуации были включены в стандарт языка, но на время написания этой книги они еще не вошли в большинство реализаций.

Суть этого понятия в том, что функция, которая обнаружила ошибку и не может справиться с нею, запускает особую ситуацию, рассчитывая, что устранить проблему можно в той функции, которая прямо или опосредованно вызывала первую. Если функция рассчитана на обработку ошибок некоторого вида, она может указать это явно, как готовность перехватить данную особую ситуацию.

Рассмотрим в качестве примера как для класса Vector можно представлять и обрабатывать особые ситуации, вызванные выходом за границу массива:

class Vector { int* p; int sz; public:

class Range { }; класс для особой ситуации

int& operator[](int i); ...

Предполагается, что объекты класса Range будут использоваться как особые ситуации, и запускать их можно так:

int& Vector::operator[](int i)

if (0<=i && i<sz) return p[i]; throw Range();

Если в функции предусмотрена реакция на ошибку недопустимого значения индекса, то ту часть функции, в которой эти ошибки будут перехватываться, надо поместить в оператор try. В нем должен быть и обработчик особой ситуации:

void f(Vector& v)

try {

do something(v); содержательная часть, работающая с v

catch (Vector::Range) {



обработчик особой ситуации Vector::Range если do something() завершится неудачно, нужно как-то среагировать на это сюда попадем только в том случае, когда

вызов do something() приведет к вызову Vector::operator[]() из- за недопустимого значения индекса

...

Обработчиком особой ситуации называется конструкция

catch ( /* ... */ ) {

Ее можно использовать только сразу после блока, начинающегося служебным словом try, или сразу после другого обработчика особой ситуации. Служебным является и слово catch. После него идет в скобках описание, которое используется аналогично описанию формальных параметров функции, а именно, в нем задается тип объектов, на которые рассчитан обработчик, и, возможно, имена параметров (см. $$9.3). Если в do something() или в любой вызванной из нее функции произойдет ошибка индекса (на любом объекте Vector), то обработчик перехватит особую ситуацию и будет выполняться часть, обрабатывающая ошибку. Например, определения следующих функций приведут к запуску обработчика в f():

void do something()

...

crash(v);

...

void crash(Vector& v)

v[v.size()+10]; искусственно вызываем ошибку индекса

Процесс запуска и перехвата особой ситуации предполагает просмотр цепочки вызовов от точки запуска особой ситуации до функции, в которой она перехватывается. При этом восстанавливается состояние стека, соответствующее функции, перехватившей ошибку, и при проходе по всей цепочке вызовов для локальных объектов функций из этой цепочки вызываются деструкторы. Подробно это описано в $$9.4.

Если при просмотре всей цепочки вызовов, начиная с запустившей особую ситуацию функции, не обнаружится подходящий обработчик, то программа завершается. Подробно это описано в $$9.7.

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

int ff(Vector& v)

try {

f(v); в f() будет перехвачена Vector::Range

catch (Vector::Range) { значит сюда мы никогда не попадем ...



1 ... 71 72 73 [ 74 ] 75 76 77 ... 120

© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика