С++ для начинающих

       

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


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

void iStack::push( int value )

{

   if ( full() )

      // value сохраняется в объекте-исключении

      throw pushOnFull( value );

   // ...

}

Выполнение инструкции throw инициирует несколько последовательных действий:

1.      Инструкция throw создает временный объект типа класса pushOnFull, вызывая его конструктор.

2.      С помощью копирующего конструктора генерируется объект-исключение типа pushOnFull – копия временного объекта, полученного на шаге 1. Затем он передается обработчику исключения.

3.      Временный объект, созданный на шаге 1, уничтожается до начала поиска обработчика.

Зачем нужно генерировать объект-исключение (шаг 2)? Инструкция

throw pushOnFull( value );

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

Поскольку объект-исключение создается путем копирования значения, переданного инструкции throw, то возбужденное исключение всегда имеет такой же тип, как и это значение:

void iStack::push( int value ) {

   if ( full() ) {

      pushOnFull except( value );

      stackExcp *pse = &except;

      throw *pse;   // объект-исключение имеет тип stackExcp

   }

   // ...

}

Выражение *pse имеет тип stackExcp. Тип созданного объекта-исключения – stackExcp, хотя pse ссылается на объект с фактическим типом pushOnFull. Фактический тип объекта, на который ссылается throw, при создании объекта-исключения не учитывается. Поэтому исключение не будет перехвачено catch-обработчиком pushOnFull.

Действия, выполняемые инструкцией throw, налагают определенные ограничения на то, какие классы можно использовать для создания объектов-исключений. Оператор throw в функции-члене push() класса iStack вызовет ошибку компиляции, если:

  • в классе pushOnFull нет конструктора, принимающего аргумент типа int, или этот конструктор недоступен;
  • в классе pushOnFull есть копирующий конструктор или деструктор, но хотя бы один из них недоступен;
  • pushOnFull – это абстрактный базовый класс. Напомним, что программа не может создавать объекты абстрактных классов (см. раздел 17.1).


  • Содержание раздела