В C++, C# и Java механизм допущений был значительно расширен. При возникновении неверных данных в критической точке вызывается не единая общесистемная функция, прерывающая выполнение программы, а пользовательская функция, которая может либо предпринять попытку разрешить проблему с данными, либо прервать выполнение программы. Возникновение проблемы в критической точке получило название исключительной ситуации или исключения, а вызываемая функция пользователя – обработчик исключения.
Рассмотрим класс, реализующий тип данных «вектор». Для получения значения элемента вектора в нем перегружается оператор [], в котором делается проверка допустимости значения индекса элемента. В качестве второго параметра функции Assert указывается метод класса, обрабатывающего исключительную ситуацию в случае, если значение индекса элемента недопустимо.
class safeVector: public vector {
public:
class outOfRangeException {
int l;
public:
outOfRangeException (const char *,
const char *, int line)
: l (line) {}
int line (void) { return l; }
};
int& safeVector::operator[] (int index) {
|
|
Assert ((index >= 0) && (index < size),
safeVector::outOfRangeException);
...
};
int process(safeVector &v, int index) {
int elem;
try {
elem = v[index];
}
catch (safeVector::outOfRangeException &e) {
cerr << "Safe Vector range exception:\n";
exit (1);
}
return elem;
}
Для того, чтобы обработчик исключения сработал, обращение к элементу массива помещается внутрь структурного блока try { }, в котором содержатся команды, результат выполнения которых потенциально может вызвать исключительную ситуацию. Затем внутри синтаксического блока catch { } определяется реакция на возникшую исключительную ситуацию outOfRangeException. Подобным образом можно определить реакцию на любую исключительную ситуацию.
Все исключительные ситуации, для которых определяются пользовательские функции-обработчики, должны быть описаны в проектной документации и протестированы. Хорошей практикой является создание отдельной группы тестов, которая генерирует различные исключительные ситуации и проверяет реакцию системы на них. Однако следует учесть, что не все исключительные ситуации могут быть промоделированы при тестировании, особенно интеграционном или системном – некоторые обработчики пишутся «про запас» - на случай изменения других модулей системы и в реальности никогда не вызываются.