11.1. Возбуждение исключения

11.1. Возбуждение исключения

Исключение – это аномальное поведение во время выполнения, которое программа может обнаружить, например: деление на 0, выход за границы массива или истощение свободной памяти. Такие исключения нарушают нормальный ход работы программы, и на них нужно немедленно отреагировать. В C++ имеются встроенные средства для их возбуждения и обработки. С помощью этих средств активизируется механизм, позволяющий двум несвязанным (или независимо разработанным) фрагментам программы обмениваться информацией об исключении.

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

#include

class iStack {

public:

iStack( int capacity )

: _stack( capacity ), _top( 0 ) { }

bool pop( int &top_value );

bool push( int value );

bool full();

bool empty();

void display();

int size();

private:

int _top;

vector _stack;

iStack выглядит следующим образом:

};

Стек реализован на основе вектора из элементов типа int. При создании объекта класса iStack его конструктор создает вектор из int, размер которого (максимальное число элементов, хранящихся в стеке) задается с помощью начального значения. Например, следующая инструкция создает объект myStack, который способен содержать не более 20 элементов типа int:

iStack myStack(20);

При манипуляциях с объектом myStack могут возникнуть две ошибки:

* запрашивается операция pop(), но стек пуст;

* запрашивается операция push(), но стек полон.

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

Во-первых, мы должны определить, какие именно исключения могут быть возбуждены. В C++ они чаще всего реализуются с помощью классов. Хотя в полном объеме классы будут представлены в главе 13, мы все же определим здесь два из них, чтобы использовать их как исключения для класса iStack. Эти определения мы поместим в заголовочный файл stackExcp.h:

// stackExcp.h

class popOnEmpty { /* ... */ };

class pushOnFull { /* ... */ };

В главе 19 исключения в виде классов обсуждаются более подробно, там же рассматривается иерархия таких классов, предоставляемая стандартной библиотекой C++.

Затем надо изменить определения функций-членов pop() и push() так, чтобы они возбуждали эти исключения. Для этого предназначена инструкция throw, которая во многих отношениях напоминает return. Она состоит из ключевого слова throw, за которым следует выражение того же типа, что и тип возбуждаемого исключения. Как выглядит инструкция throw для функции pop()? Попробуем такой вариант:

// увы, это не совсем правильно

throw popOnEmpty;

К сожалению, так нельзя. Исключение – это объект, и функция pop() должна генерировать объект класса соответствующего типа. Выражение в инструкции throw не может быть просто типом. Для создания нужного объекта необходимо вызвать конструктор класса. Инструкция throw для функции pop() будет выглядеть так:

// инструкция является вызовом конструктора

throw popOnEmpty();

Эта инструкция создает объект исключения типа popOnEmpty.

Напомним, что функции-члены pop() и push() были определены как возвращающие значение типа bool: true означало, что операция завершилась успешно, а false – что произошла ошибка. Поскольку теперь для извещения о неудаче pop() и push() используют исключения, возвращать значение необязательно. Поэтому мы будем считать, что эти функции-члены имеют тип void:

class iStack {

public:

// ...

// больше не возвращают значения

void pop( int &value );

void push( int value );

private:

// ...

};

Теперь функции, пользующиеся нашим классом iStack, будут предполагать, что все хорошо, если только не возбуждено исключение; им больше не надо проверять возвращенное значение, чтобы узнать, как завершилась операция. В двух следующих разделах мы покажем, как определить функцию для обработки исключений, а сейчас представим новые реализации функций-членов pop() и push() класса iStack:

#include "stackExcp.h"

void iStack::pop( int &top_value )

{

if ( empty() )

throw popOnEmpty();

top_value = _stack[ --_top ];

cout "iStack::pop(): "top_value " endl;

}

void iStack::push( int value )

{

cout "iStack::push( " value " ) ";

if ( full() )

throw pushOnFull( value );

_stack[ _top++ ] = value;

}

Хотя исключения чаще всего представляют собой объекты типа класса, инструкция throw может генерировать объекты любого типа. Например, функция mathFunc() в следующем примере возбуждает исключение в виде объекта-перечисления . Это корректный код C++:

enum EHstate { noErr, zeroOp, negativeOp, severeError };

int mathFunc( int i ) {

if ( i == 0 )

throw zeroOp; // исключение в виде объекта-перечисления

// в противном случае продолжается нормальная обработка

}

Упражнение 11.1

Какие из приведенных инструкций throw ошибочны? Почему? Для правильных инструкций укажите тип возбужденного исключения:

(a) class exceptionType { };

throw exceptionType();

(b) int excpObj;

throw excpObj;

(c) enum mathErr { overflow, underflow, zeroDivide };

throw mathErr zeroDivide();

(d) int *pi = excpObj;

throw pi;

Упражнение 11.2

У класса IntArray, определенного в разделе 2.3, имеется функция-оператор operator[](), в которой используется assert() для извещения о том, что индекс вышел за пределы массива. Измените определение этого оператора так, чтобы в подобной ситуации он генерировал исключение. Определите класс, который будет употребляться как тип возбужденного исключения.

Поделитесь на страничке

Следующая глава >

Похожие главы из других книг

Исключения

Из книги Сущность технологии СОМ. Библиотека программиста автора Бокс Дональд

Исключения СОМ имеет специфическую поддержку выбрасывания (throwing) исключительных ситуаций из реализации методов. Поскольку в языке C++ не существует двоичного стандарта для исключений, СОМ предлагает явные API-функции для выбрасывания и перехвата объектов СОМ-исключений://


Исключения не работают

Из книги Все под контролем: Кто и как следит за тобой автора Гарфинкель Симеон

Исключения не работают Вернемся к Ассоциации прямого маркетинга. Конни Ламатто [Connie LaMatto] утверждает, что индустрия прямых продаж разработала специальную систему в помощь тем «редким» людям, которые не хотят получать предложения. Это так называемая Служба почтовых


Внутренние исключения

Из книги Язык программирования С# 2005 и платформа .NET 2.0. [3-е издание] автора Троелсен Эндрю

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


Тип исключения

Из книги Microsoft Visual C++ и MFC. Программирование для Windows 95 и Windows NT автора Фролов Александр Вячеславович

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


Исключения

Из книги Основы объектно-ориентированного программирования автора Мейер Бертран

Исключения Вооружившись понятием отказа, можно теперь определить понятие "исключение". Программа приводит к отказу из-за возникновения некоторых специфических событий (арифметического переполнения, нарушения спецификаций), прерывающих ее выполнение. Такие события и


Дисциплинированные исключения

Из книги Программирование на языке Ruby [Идеология языка, теория и практика применения] автора Фултон Хэл

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


1.2.7. Исключения

Из книги Firebird РУКОВОДСТВО РАЗРАБОТЧИКА БАЗ ДАННЫХ автора Борри Хелен


Исключения

Из книги Мир InterBase. Архитектура, администрирование и разработка приложений баз данных в InterBase/FireBird/Yaffil автора Ковязин Алексей Николаевич

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


11.3.1. Объекты-исключения

Из книги автора

11.3.1. Объекты-исключения Объявлением исключения в catch-обработчикемогут быть объявления типа или объекта. В какихслучаях это следует делать? Тогда, когда необходимополучить значение или как-то манипулировать объектом,созданным в выражении throw. Если классы исключений


11.3.3. Повторное возбуждение исключения

Из книги автора

11.3.3. Повторное возбуждение исключения Может оказаться так, что в одном предложении catch не удалось полностью обработать исключение. Выполнив некоторые корректирующие действия, catch-обработчик может решить, что дальнейшую обработку следует поручить функции, расположенной


19.2. Исключения и наследование

Из книги автора

19.2. Исключения и наследование Обработка исключений – это стандартное языковое средство для реакции на аномальное поведение программы во время выполнения. C++ поддерживает единообразный синтаксис и стиль обработки исключений, а также способы тонкой настройки этого


19.2.2. Возбуждение исключения типа класса

Из книги автора

19.2.2. Возбуждение исключения типа класса Теперь, познакомившись с классами, посмотрим, что происходит, когда функция-член push() нашего iStack возбуждает исключение:void iStack::push( int value ){if ( full() )// value сохраняется в объекте-исключенииthrow pushOnFull( value );// ...}* Выполнение инструкции throw


26.7. Взаимные исключения

Из книги автора

26.7. Взаимные исключения Обратите внимание на то, что в листинге 26.8 при завершении выполнения очередного потока в главном цикле уменьшаются на единицу и nconn, и nlefttoread. Мы могли бы поместить оба эти оператора уменьшения в одну функцию do_get_read, что позволило бы каждому потоку