Особая ситуация перехватывается благодаря своему типу. Однако, запускается ведь не тип, а объект. Если нам нужно передать некоторую информацию из точки запуска в обработчик, то для этого ее следует поместить в запускаемый объект. Например, допустим нужно знать значение индекса, выходящее за границы диапазона:
class Vector { // ... public: class Range { public: int index; Range(int i) : index(i) { } }; // ... int& operator[](int i) // ... };
int Vector::operator[](int i) { if (o<=i && i <sz) return p[i]; throw Range(i); }
Чтобы исследовать недопустимое значение индекса, в обработчике нужно дать имя объекту, представляющему особую ситуацию:
void f(Vector& v) { // ...
try { do_something(v); } catch (Vector::Range r ) { cerr << "недопустимый индекс" << r.index << '\n'; // ... } // ... }
Конструкция в скобках после служебного слова catch является по сути описанием и она аналогична описанию формального параметра функции. В ней указывается каким может быть тип параметра (т.е. особой ситуации) и может задаваться имя для фактической, т.е. запущенной, особой ситуации. Вспомним, что в шаблонах типов у нас был выбор для именования особых ситуаций. В каждом созданном по шаблону классе был свой класс особой ситуации:
template<class T> class Allocator { // ... class Exhausted { } // ... T* get(); };
void f(Allocator<int>& ai, Allocator<double>& ad) { try { // ... } catch (Allocator<int>::Exhausted) { // ... } catch (Allocator<double>::Exhausted) { // ... } }
С другой стороны, особая ситуация может быть общей для всех созданных по шаблону классов:
class Allocator_Exhausted { };
template<class T> class Allocator { // ... T* get(); };
void f(Allocator<int>& ai, Allocator<double>& ad) { try { // ... } catch (Allocator_Exhausted) { // ... } }
Какой способ задания особой ситуации предпочтительней, сказать трудно. Выбор зависит от назначения рассматриваемого шаблона.