Чтение онлайн

на главную - закладки

Жанры

Шрифт:

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

Есть четыре подхода к проблеме, что же делать, когда во время выполнения универсальное средство вроде slist сталкивется с ошибкой (в С++ нет никаких специальных средств языка для обработки ошибок):

1. Возвращать недопустимое значение и позволить пользвателю его проверять

2. Возвращать дополнительное значение состояния и рарешить пользователю проверять его

3. Вызывать функцию ошибок, заданную как часть класса slist или

4. Вызывать функцию ошибок, которую предположительно предоставляет пользователь.

Для

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

Первый подход, возвращать недопустимое значение, неосществим. Нет совершенно никакого способа узнать, что некоторое конкретное значение будет недопустимым во всех прменениях slist.

Второй подход, возвращать значение состояния, можно ипользовать в некоторых классах (один из вариантов этого плана применяется в стандартных потоках ввода/вывода istream и ostream; как – объясняется в #8.4.2). Здесь, однако, имеется серьезная проблема, вдруг пользователь не позаботится проврить значение состояния, если средство не слишком часто поводит. Кроме того, средство может использоваться в сотнях или даже тысячах мест программы. Проверка значения в каждом месте сильно затруднит чтение программы.

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

Четвертый подход, позволить пользователю задавать фунцию ошибок, имеет некоторую привлекательность при условии, что разработчик предоставляет класс в виде библиотеки (#4.5), в которой содержатся стандартные функции обработки ошибок.

Решения 3 и 4 можно сделать более гибкими (и по сути эвивалентными), задав указатель на функцию, а не саму функцию. Это позволит разработчику такого средства, как slist, предотавить функцию ошибок, действующую по умолчанию, и при этом программистам, которые будут использовать списки, будет легко задать свои собственные функции ошибок, когда нужно, и там, где нужно. Например:

typedef void (*PFC)(char*); // указатель на тип функция extern PFC slist_handler; extern PFC set_slist_handler(PFC);

Функция set_slist_hanlder позволяет пользователю замнить стандартную функцию. Общепринятая реализация предосталяет действующую по умолчанию функцию обработки ошибок, котрая сначала пишет сообщение об ошибке в cerr, после чего завершает программу с помощью exit:

#include «slist.h» #include «stream.h»

void default_error(char* s)

(* cerr «„ s «« «\n“; exit(1); *)

Она описывает также указатель на функцию ошибок и, для удобства записи, функцию для ее установки:

PFC slist_handler = default_error;

PFC set_slist_handler(PFC handler); (* PFC rr = slist_handler; slist_handler = handler; return rr; *)

Обратите внимание, как set_slist_hanlder возвращает предыдущий slist_hanlder. Это делает удобным установку и переустановку обработчиков ошибок на манер стека. В основном это может быть полезным в больших программах, в которых slist может

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

(* PFC old = set_slist_handler(my_handler);

// код, в котором в случае ошибок в slist // будет использоваться мой обработчик my_handler

set_slist_handler(old); // восстановление *)

Чтобы сделать управление более изящным, slist_hanlder мог бы быть сделан членом класса slist, что позволило бы раличным спискам иметь одновременно разные обработчики.

7.3.5 Обобщенные классы

Очевидно, можно было бы определить списки других типов (classdef*, int, char* и т.д.) точно так же, как был опредлен класс nlist: простым выводом из класса slist. Процесс оределения таких новых типов утомителен (и потому чреват ошиками), но с помощью макросов его можно «механизировать». К сожалению, если пользоваться стандартным C препроцессором (#4.7 и #с.11.1), это тоже может оказаться тягостным. Однако полученными в результате макросами пользоваться довольно просто.

Вот пример того, как обобщенный (generic) класс slist, названный gslist, может быть задан как макрос. Сначала для написания такого рода макросов включаются некоторые инстрменты из «generic.h»:

#include «slist.h»

#ifndef GENERICH #include «generic.h» #endif

Обратите внимание на использование #ifndef для того, чтобы гарантировать, что «generic.h» в одной компиляции не будет включен дважды. GENERICH определен в «generic.h».

После этого с помощью name2, макроса из «generic.h» для конкатенации имен, определяются имена новых обобщенных

классов:

#define gslist(type) name2(type,gslist) #define gslist_iterator(type) name2(type,gslist_iterator)

И, наконец, можно написать классы gslist(тип) и gslist_iterator(тип):

#define gslistdeclare(type) \ struct gslist(type) : slist (* \ int insert(type a) \ (* return slist::insert( ent(a) ); *) \ int append(type a) \ (* return slist::append( ent(a) ); *) \ type get (* return type( slist::get ); *) \ gslist(type) (* *) \ gslist(type)(type a) : (ent(a)) (* *) \ ~gslist(type) (* clear; *) \ *); \ \ struct gslist_iterator(type) : slist_iterator (* \ gslist_iterator(type)(gslist(type) amp; a) \ : ( (slist amp;)s ) (**) \ type operator \ (* return type( slist_iterator::operator ); *)\ *)

\ на конце строк указывает , что следующая строка явлется частью определяемого макроса.

С помощью этого макроса список указателей на имя, аналгичный использованному раньше классу nlist, можно определить так:

#include «name.h»

typedef name* Pname; declare(gslist,Pname); // описывает класс gslist(Pname)

gslist(Pname) nl; // описывает один gslist(Pname)

Макрос declare (описать) определен в «generic.h». Он конкатинирует свои параметры и вызывает макрос с этим именем, в данном случае gslistdeclare, описанный выше. Параметр имя типа для declare должен быть простым именем. Используемый мтод макроопределения не может обрабатывать имена типов вроде name*, поэтому применяется typedef.

Поделиться:
Популярные книги

Сама себе хозяйка

Красовская Марианна
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Сама себе хозяйка

Сердце Дракона. Том 11

Клеванский Кирилл Сергеевич
11. Сердце дракона
Фантастика:
фэнтези
героическая фантастика
боевая фантастика
6.50
рейтинг книги
Сердце Дракона. Том 11

Первый среди равных. Книга IV

Бор Жорж
4. Первый среди Равных
Фантастика:
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Первый среди равных. Книга IV

Неучтенный. Дилогия

Муравьёв Константин Николаевич
Неучтенный
Фантастика:
боевая фантастика
попаданцы
7.98
рейтинг книги
Неучтенный. Дилогия

Мастер Разума IV

Кронос Александр
4. Мастер Разума
Фантастика:
боевая фантастика
попаданцы
аниме
5.00
рейтинг книги
Мастер Разума IV

Авиатор: назад в СССР

Дорин Михаил
1. Авиатор
Фантастика:
попаданцы
альтернативная история
5.25
рейтинг книги
Авиатор: назад в СССР

Кадры решают все

Злотников Роман Валерьевич
2. Элита элит
Фантастика:
боевая фантастика
попаданцы
альтернативная история
8.09
рейтинг книги
Кадры решают все

Плеяда

Суконкин Алексей
Проза:
военная проза
русская классическая проза
5.00
рейтинг книги
Плеяда

Потусторонний. Книга 2

Погуляй Юрий Александрович
2. Господин Артемьев
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Потусторонний. Книга 2

Ученик. Книга 4

Первухин Андрей Евгеньевич
4. Ученик
Фантастика:
фэнтези
5.67
рейтинг книги
Ученик. Книга 4

Законник Российской Империи. Том 3

Ткачев Андрей Юрьевич
3. Словом и делом
Фантастика:
городское фэнтези
альтернативная история
аниме
дорама
5.00
рейтинг книги
Законник Российской Империи. Том 3

Ваше Сиятельство 7

Моури Эрли
7. Ваше Сиятельство
Фантастика:
боевая фантастика
аниме
5.00
рейтинг книги
Ваше Сиятельство 7

Война

Валериев Игорь
7. Ермак
Фантастика:
боевая фантастика
альтернативная история
5.25
рейтинг книги
Война

Младший сын князя. Том 4

Ткачев Андрей Юрьевич
4. Аналитик
Фантастика:
фэнтези
аниме
5.00
рейтинг книги
Младший сын князя. Том 4