Порождение и перехват
Для порождения исключений используется оператор
throw выражение;
Рекомендуется указывать в качестве аргумента объекты специальных классов, а не стандартных типов (
int) или классов общего назначения (
vector). Классы исключений рекомендуется выстраивать в иерархии.
Операторы, которые могут генерировать исключения, записываются внутри блока
try, после которого идет набор обработчиков исключений
catch. У каждого обработчика указывается тип исключений, который он может перехватывать, и опционально имя, с помощью которого можно обращаться к созданному оператором
throw объекту внутри обработчика.
Перехват исключения рекомендуется делать по ссылке, чтобы избежать
срезки объекта при преобразовании к базовому классу.
try
{ //
}
catch(bad_alloc &)
{ //
}
catch(io_error & e)
{ e.stream.clear(); //
}
catch(exception &)
{ //
}
Порядок обработки исключений следующий:
- Создается копия аргумента throw в статической памяти.
- Происходит поиск подходящего обработчика. В процессе поиска выполняется раскрутка стека, т.е. выход из функций, где нет подходящих обработчиков и вызов деструкторов для локальных объектов.
- Если подходящий обработчик найден, управление передается ему, иначе вызывается функция terminate, которая по умолчанию аварийно завершает программу, но можно задать другое действие с помощью функции set_terminate
- После выполнения обработчика копия аргумента throw в статической памяти уничтожается и управление передается на оператор, следующий за последним из обработчиков того набора, где был найден обработчик.
Если обработчик не смог полностью обработать исключение, то можно повторно сгенерировать исключение внутри обработчика с помощью оператора
throw;
Проверка на соответствие типа объекта и обработчика выполняется в порядке перечисления обработчиков, поэтому обработчики для исключений производных классов должны быть указаны до обработчиков базовых классов. Самым последним обработчиком в наборе может быть указан
catch(...), который перехватывает все исключения. Такой обработчик можно использовать для корректного освобождения ресурсов:
int g(int n)
{
int * a;
a=new int[n];
try
{ //
}
catch(...)
{ delete[] a;
throw;
}
delete[] a;
}
Если функция не возвращает исключений, то можно указать это в заголовке:
void f() noexcept;
Рекомендуется, чтобы деструктор не возвращал исключений, так как деструкторы вызываются при раскрутке стека и возникновение исключений в этот момент приведет к вызову
terminate и аварийному завершению программы.