Void f1(int) throw(); // исключений не ожидается 


Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

Void f1(int) throw(); // исключений не ожидается



int f2(double, char*) throw(const char *);

// только исключения типа const char *

double f3(void) throw(int, char, A);

// исключения встроенных типов int, char и пользовательского типа A

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


7.3. Специальные средства поддержки механизма
исключений

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

Как было указано выше, при отсутствии подходящего обработчика для исключения вызывается функция terminate, которая, в свою очередь, передает управление функции abort, принудительно завершающей программу. Эта функция входит в стандартную библиотеку С++ и описана в заголовочном файле exceptio.h. Функция terminate также вызывается и в ряде других случаев: например, когда при развязке стека в деструкторе одного из объектов возникает исключение или когда возбуждается исключение в конструкторе или деструкторе нелокального объекта, или же при попытке ретранслировать с помощью оператора throw; несуществующий объект-исключение.

Программист может переопределить функцию terminate, более точно, назначить вместо нее собственную функцию. Задать собственную функцию взамен terminate можно стандартной функцией set_terminate. Эта функция при вызове возвращает указатель на старую функцию terminate и принимает указатель на новую. Новая функция должна задаваться указателем предопределенного типа terminate_function, который описан в заголовочном файле except.h следующим образом:

typedef void (* terminate_function) ();

Как видно из этого описания, определяемая функция не должна принимать параметров и возвращать значений.

Прототип функции set_terminate() выглядит следующим образом:

terminate_function set_terminate(terminate_function func_name);

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

Ниже дан пример введения новой функции завершения.

Пример

#include<stdlib.h>

#include<except.h>

...

void new_terminate() // новая функция

{

Пользовательский код

abort();

}

Void main()

{

// задание указателя на новую функцию

terminate_function p_new_terminate = new_terminate;

terminate_function p_old_terminate = set_terminate(p_new_terminate);

...

Throw; // генерация исключения вне контролируемых блоков

// вызывается функция new_terminate()

...

}

Еще одной стандартной функцией поддержки исключений является функция unexpected. Функция unexpected вызывается в случае возникновения в некоторой функции не предусмотренного ее спецификацией исключения. Функция unexpected не имеет параметров и не возвращает значений, но может генерировать и даже ретранслировать исключения. Если передаваемое из нее исключение согласуется с ранее нарушенной спецификацией, то поиск обработчика исключения продолжается. Если же не согласуется, то возможны два случая: 1) при отсутствии в нарушенной спецификации исключения std::bad_exception вызывается функция terminate; 2) при наличии std::bad_exception текущее необработанное исключение замещается исключением std::bad_exception и поиск обработчика продолжается уже для него.

Функция unexpected, как и terminate, может быть замещена пользовательской функцией. Для задания собственного варианта функции unexpected необходимо вызвать функцию set_unexpected с прототипом вида:

unexpected_function set_unexpected(unexpected_function func_name);

Параметром в эту функцию необходимо передать указатель на новую функцию, при этом указатель на старую функцию будет возвращен в качестве результата. Сам указатель имеет стандартный тип unexpected_function:

typedef void (* unexpected_function) ();

и описан в заголовочном файле except.h.

Новая функция unexpected может вызывать другие функции, например, abort, exit и terminate.

Чтобы определить наличие необработанного исключения, стандарт вводит специальную функцию uncaught_exception[41]. Эта функция не имеет параметров. Возвращаемое значение имеет тип bool. При наличии необработанного исключения функция возвращает значение true, при отсутствии false.

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

class exception {

public:

exception () throw();

exception (const exception&) throw();

exception& operator= (const exception&) throw();

virtual ~exception () throw();

virtual const char* what () const throw();

};

Класс exception имеет два основных подкласса, а именно logic_error и runtime_error. От них, в свою очередь, образуются специальные классы исключений: domain_error, invalid_argument, length_error, out_of_range (от logic_error) и range_error, overflow_error, underflow_error (от runtime_error). Кроме перечисленных классов определены следующие стандартные классы исключений: bad_alloc (связан с ошибками при выделении динамической памяти); bad_cast (используется при ошибках операций преобразования типов); bad_typeid (служит для представления ошибок идентификации типов); bad_exception (применяется для повторно генерируемых исключений).

Использование иерархии классов позволяет более точно классифицировать причины возникновения исключений и осуществлять выборочную обработку. Исключения базовых классов включают в себя все исключения производных классов, например, исключение domain_error есть частный случай logic_error, которое, в свою очередь, есть частный случай exception. Добавляя к иерархии новые классы, можно получать новые частные случаи исключений. Единственное, о чем следует помнить, – исключения более общих классов должны «отлавливаться» после частных исключений, иначе все частные случаи исключений будут обрабатываться по общему «сценарию».

Для дополнительной поддержки механизма исключений в заголовочном файле except.h имеются также внешние переменные __throwExceptionName, __throwFileName, __throwLineNumber:

extern char * __throwExceptionName;

extern char * __throwFileName;

extern unsigned __throwLineNumber;

__throwExceptionName содержит имя типа последнего исключения, порожденного программой; __throwFileName хранит имя файла с исходным текстом программы, в котором возникло последнее исключение, а __throwLineNumber инициализируется номером строки в исходном файле, где было сгенерировано исключение.


Вопросы для самопроверки

 

1. Что понимается под исключительной ситуацией в С++?

2. Чем отличается механизм исключений от традиционного механизма обработки ошибок (который используется, например, в языке С)?

3. Как заключить группу операторов в контролируемый блок? Приведите пример.

4. Каким образом записывается декларация типа исключения в заголовке блока catch? Дайте общий формат и пример.

5. Опишите процесс генерации и передачи исключения в обработчик.

6. Что понимается под развязкой стека?

7. Как осуществляется ретрансляция сгенерированного исключения?

8. Какова продолжительность существования объекта-исключения?

9. Почему захват исключения по ссылке представляется наиболее эффективным? Обоснуйте ответ.

10. Почему обработчик исключения catch(...) должен всегда быть последним в цепочке обработчиков?

11. Каково назначение спецификации исключений в функциях?

12. Приведите примеры определения (описания) глобальной и компонентной функций со спецификацией исключений.

13. Охарактеризуйте свойства функции со спецификацией исключений вида throw().

14. Имеется функция void f() throw(). Можно ли в ней вызвать функцию с заголовком вида void g() throw(CSomeException)? Поясните ответ.

15. Имеется класс C и производный от него класс D. В первом классе есть функция с заголовком virtual bool C::f() throw(), а во втором – функция с заголовком bool D::f() throw(CSomeException). Правильно ли описаны эти функции? Обоснуйте ответ.

16. Каковы последствия нарушения спецификации исключений в функциях?

17. Каково назначение функций terminate и abort?

18. Каким образом задать пользовательскую функцию вместо terminate? Приведите фрагмент кода.

19. Перечислите случаи, когда происходит автоматический вызов функции terminate.

20. Для чего нужна функция unexpected?

21. Как можно заменить функцию unexpected собственной функцией? Запишите фрагмент кода.

22. Как определить наличие в текущей точке программного кода необработанного исключения?

23. Какие классы исключений имеются в стандартной библиотеке С++?

24. Охарактеризуйте назначение класса std::bad_exception.

25. Определите собственный класс исключений и покажите его использование на примере.

26. Почему исключения в конструкторах и деструкторах наиболее опасны? Дайте обоснованный ответ.

 

Задачи

 

Перепишите шаблоны задач 2 и 3 из главы 5 так, чтобы работа с ними была максимально безопасна, используя механизм исключений. Покажите использование новых шаблонов в штатном режиме и при наличии исключений. Оцените издержки, вносимые механизмом исключений.

 


Подсчет ссылок

Подсчет ссылок является фундаментальным методом, который широко используется в рамках объектной технологии[42]. Он определяет правила, согласно которым несколько объектов с одинаковым значением работают с общей для них копией этого значения. Подсчет ссылок дает два ключевых преимущества. Во-первых, он позволяет уменьшить затраты памяти на хранение данных объектов. Во-вторых, он облегчает учет ресурсов динамической памяти при создании и удалении объектов.



Поделиться:


Последнее изменение этой страницы: 2016-08-14; просмотров: 202; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 18.119.105.239 (0.014 с.)