C++ для начинающих.

19.2.7. Конструкторы и функциональные try-блоки.

Можно объявить функцию так, что все ее тело будет заключено в try-блок. Такие try-блоки называются функциональными. (Мы упоминали их в разделе 11.2.) Например:

Int main() {

Try {

// тело функции main().

}

Catch ( pushOnFull ) {

// ...

}

Catch ( popOnEmpty ) {

// ...

}

Функциональный try-блок ассоциирует группу catch-обработчиков с телом функции. Если инструкция внутри тела возбуждает исключение, то поиск его обработчика ведется среди тех, что следуют за телом функции.

Функциональный try-блок необходим для конструкторов класса. Почему? Определение конструктора имеет следующий вид:

Имя_класса( список_параметров ).

// список инициализации членов:

: член1(выражение1 ) , // инициализация член1.

Член2(выражение2 ) , // инициализация член2.

// тело функции:

{ /* ... */ }.

Выражение1 и выражение2 могут быть выражениями любого вида, в частности функциями, которые возбуждают исключения.

Рассмотрим еще раз класс Account, описанный в главе 14. Его конструктор можно переопределить так:

Nline Account::

Account( const char* name, double opening_bal ).

: _balance( opening_bal - ServiceCharge() ).

{

_name = new char[ strlen(name) + 1 ];

Strcpy( _name, name );

_acct_nmbr = get_unique_acct_nmbr();

}

Функция ServiceCharge(), вызываемая для инициализации члена _balance, может возбуждать исключение. Как нужно реализовать конструктор, если мы хотим обрабатывать все исключения, возбуждаемые функциями, которые вызываются при конструировании объекта типа Account?

Помещать try-блок в тело функции нельзя:

Inline Account::

Account( const char* name, double opening_bal ).

: _balance( opening_bal - ServiceCharge() ).

{

Try {

_name = new char[ strlen(name) + 1 ];

Strcpy( _name, name );

_acct_nmbr = get_unique_acct_nmbr();

}

Catch (...) {

// специальная обработка.

// не перехватывает исключения,

// возбужденные в списке инициализации членов.

}

}

Поскольку try-блок не охватывает список инициализации членов, то catch-обработчик, находящийся в конце конструктора, не рассматривается при поиске кандидатов, которые способны перехватить исключение, возбужденное в функции ServiceCharge().

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

Inline Account::

Account( const char* name, double opening_bal ).

Try.

: _balance( opening_bal - ServiceCharge() ).

{

_name = new char[ strlen(name) + 1 ];

Strcpy( _name, name );

_acct_nmbr = get_unique_acct_nmbr();

}

Catch (...) {

// теперь специальная обработка.

// перехватывает исключения,

// возбужденные в ServiceCharge().

}

Обратите внимание, что ключевое слово try находится перед списком инициализации членов, а составная инструкция, образующая try-блок, охватывает тело конструктора. Теперь предложение catch(...) принимается во внимание при поиске обработчика исключения, возбужденного как в списке инициализации членов, так и в теле конструктора.