Как мы знаем, инициализировать поля класса можно с помощью списка инициализации (см. листинг 2.7), причем в качестве инициализирующего выражения может стоять вызов функции или явный вызов конструктора. Тогда возникает естественный вопрос: а что, если при выполнении инициализирующих выражений в списке возникнет исключение? Хорошо бы перехватить и обработать его тут же, в конструкторе. Однако контролируемый блок try...catch не позволяет справиться с этой проблемой, так как он определяется в теле конструктора, а список инициализации находится вне тела и выполняется до начала выполнения тела.
Специально для решения этой проблемы был придуман и внесен в стандарт контролируемым блок, являющийся телом функции. В стандарте такой блок имеет название function-try-block, что можно перевести как «контролируемый блок-функция». В стандарте (см. п. п. 15/3 в [1]) приводится следующий пример, представленный в листинге 7.11.
Листинг 7 11. Контролируемый блок — тело конструктора
int f(int); class С
{ int i; double d; public:
C(int, double); // ...
};
C: :C(int ii. double id) try
:i(f(ii)), d(id)
{ // ...
}
catch(...)
// функция, определенная в другом месте // поля
// конструктор инициализации
// реализация конструктора
// контролируем
// список инициализации
// тело конструктора
// обработчик исключений
Обратите внимание, что слово try написано перед списком инициализации конструктора — этим подчеркивается, что список инициализации контролируется. Любое исключение, которое сгенерирует функция f (), будет перехвачено и обработано в секции-ловушке. При такой организации конструктора отсутствуют операторы после блока try...catch. Но они и не нужны, так как если конструктор перехватил исключение, значит, объект «не доделан» и нормального завершения конструирования ждать не приходится. Выход из такой ситуации только один — выполнить ту обработку, которая возможна, и послать исключение дальше, выполнив один из операторов:
• throw без аргумента — перехваченное исключение транслируется далее;
• throw с аргументом — генерируется новое исключение.
Интересно, что можно объявить контролируемый блок-функцию в любой функции. Например, мы можем контролировать все исключения, возникающие в теле главной функции, написав такую конструкцию:
int main()
try { // контролируемый блок - тело функции ... }
catch(...)
{ // сообщения об исключениях ...
}
Если в контролируемом блоке не возникнет исключений, то блок функции нормально завершается. Если же исключения возникнут, то, как обычно, выполняется секция-ловушка, и только после этого программа завершается. Секций-ловушек, естественно, может быть прописано столько, сколько необходимо.
Если подобная конструкция используется в обычной функции или в методе, то выйти из секции-ловушки разрешается обычным оператором возврата return.
ПРИМЕЧАНИЕ
Не все компиляторы поддерживают контролируемый блок-функцию. Например, в компиляторе Borland С++ Builder 6 эта форма блока try не поддерживается. |