Предлагаемое в C++ решение проблемы реакции на синхронные исключительные ситуации связано с использованием так называемых контролируемых блоков операторов.
Операторы, составляющие критические участки кода (например, вызов функций, в которых могут возникнуть исключительные ситуации) и операторы, определяющие перехват возможных исключений, размещаются в этих блоках отдельно от прочих "безопасных" операторов функции.
Синтаксис контролируемых блоков описывается следующим множеством формул Бэкуса-Наура:
Оператор ::= КонтролируемыйБлокОператоров
КонтролируемыйБлокОператоров ::= try СоставнойОператор СписокРеакций
СписокРеакций ::= Реакция [СписокРеакций]
Реакция ::= catch (ОбъявлениеИсключения) СоставнойОператор
ОбъявлениеИсключения ::= СписокСпецификаторовТипа Описатель
::= СписокСпецификаторовТипа АбстрактныйОписатель
::= СписокСпецификаторовТипа
::= ...
Это одно из последних множеств БНФ на нашем пути. Всё те же знакомые описатели, любимые абстрактные описатели, и даже хорошо известное многоточие.
На основе данных БНФ строим контролируемый блок операторов. Как всегда, пока важен лишь внешний вид оператора.
КонтролируемыйБлокОператоров
try СоставнойОператор СписокРеакций
try { Оператор Оператор Оператор } СписокРеакций try { int retVal; retVal = MyFun(255); cout << "retVal == " << retVal << "…" << endl } catch (ОбъявлениеИсключения) СоставнойОператор
СписокРеакций try { int retVal; retVal = MyFun(255); cout << "retVal == " << retVal << "..." << endl } catch (char *) { x = x * 25; } catch (MyException MyProblem1) { cout << "Неполадки типа MyException: " << MyProblem1.text << endl; } catch (...) { cout << "Нераспознанные исключения..." << endl; }
Итак, контролируемый блок операторов. Прежде всего, это блок операторов, то есть, составной оператор. Его место - тело функции. Этот оператор может входить в любой другой блок операторов.
Он начинается с ключевого слова try (поэтому дальше мы его будем называть try-блоком), следом за которым располагается так называемый блок испытания. В блоке испытания обычно размещается критический код, выполнение которого может привести к возникновению ошибки времени выполнения.
За ним следует, по крайней мере, один элемент списка реакций со своим блоком перехвата. Каждый блок перехвата начинается с заголовка - ключевого слова catch, за которым в круглых скобках располагается объявление ситуации. Синтаксис объявления ситуации напоминает объявление параметра в прототипе функции. В этом объявлении не используется лишь инициализаторы.
catch-блок содержит код, предназначенный для перехвата исключений. Однако без генератора исключений он абсолютно бесполезен.
Возбуждение (или генерация) исключения обеспечивается операцией throw. Это весьма странная операция. Даже с точки зрения синтаксиса: