Исключения, которые генерируются функциями, вызванными из try-блока, могут быть в нём обработаны. Например:
#include <iostream>
using namespace std;
void func1()
{
cout << "Executing func1\n";
throw "func1";
}
void func2()
{
try
{
cout << "Executing func2\n";
throw "func2";
}
catch (const char* ex)
{
cerr << "Catch exception " << ex << " from func2\n";
}
}
void main()
{
for (int i = 1; i <= 2; i++)
{
try
{
if (i == 1)
func1();
else
func2();
cout << "i = " << i << '\n';
}
catch (const char* ex)
{
cerr << "Catch exception " << ex << " from main\n";
}
cout << '\n';
}
system("Pause");
}
В результате выполнения этой программы на экран будет выведено:
Executing func1
Catch exception func1 from main
Executing func2
Catch exception func2 from func2
i = 2
Здесь функции func1 и func2 вызываются из try-блока в main. В func1 генерируется исключение, обработка которого внутри самой функции не предусмотрена. Поэтому исключение "func1" передаётся в основную программу, где перехватывается обработчиком try-блока, из которого func1 была вызвана. Поскольку выброс исключения сразу передает управление в соответствующий catch-блок, вывода на экран значения переменной i не произойдет.
При вызове func2 также генерируется исключение, но в этой функции предусмотрена обработка исключений такого типа. Поэтому исключение "func2" будет перехвачено и обработано внутри самой функции func2. После этого продолжится нормальное выполнение программы, т.е. вывод на экран значения переменной i и переход к следующей итерации цикла (которой не будет, т.к. условие продолжения цикла не выполнится).
В С++ существует возможность ограничения типов исключений, которые может генерировать функция. Для этого при объявлении функции список типов исключений указывается с помощью ключевого слова throw следующим образом:
После ключевого слова throw в скобках указывается перечень типов данных, которые могут быть использованы для генерации исключения в этой функции. Например, функция func1 может быть объявлена следующим образом:
void func1() throw(char*, const char*)
Теперь внутри функции func1 можно генерировать только исключения строковых типов – char* и const char*. Если будет выброшено необработанное исключение любого другого типа, программа будет аварийно остановлена.
Если при объявлении функции указать пустой список возможных типов исключений (throw()), то функции запрещено будет генерировать любые типы исключений.
Если в списке throw указано многоточие, то функция может генерировать любые исключения (поведение по умолчанию).
Предостережение! В компиляторе Visual Studio до 2010 версии включительно не реализована возможность ограничения исключений указанным списком. Компилятор корректно обрабатывает списки вида throw() и throw(...), т.е. дает возможность запретить или разрешить все исключения. Если же в скобках указывается список типов, то он игнорируется и обрабатывается компилятором как throw(...), т.е. функции позволяется генерировать любые исключения.
Следует понимать, что список ограничений работает только для исключений, которые «выходят за пределы» функции, т.е. не могут быть обработаны в ней самой. Например, пусть функции из предыдующего примера будут объявлены следующим образом:
void func1() throw(int)
void func2() throw(int)
Функциям позволено генерировать исключения только типа int. В этом случае вызов первой функции, которая выбросит исключение const char*, приведёт к аварийному завершению программы. А вторая функция отработает нормально, поскольку исключение const char*, которое она генерирует, обрабатывается внутри самой этой функции, не передаваясь «наружу».