Бьерн Страуструп - Язык программирования С++. Главы 8-10 - Имена особых ситуаций

ОГЛАВЛЕНИЕ


9.3 Имена особых ситуаций

Особая ситуация перехватывается благодаря своему типу. Однако, запускается ведь не тип, а объект. Если нам нужно передать некоторую информацию из точки запуска в обработчик, то для этого ее следует поместить в запускаемый объект. Например, допустим нужно знать значение индекса, выходящее за границы диапазона:
        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) {
            // ...
         }
       }
Какой способ задания особой ситуации предпочтительней, сказать трудно. Выбор зависит от назначения рассматриваемого шаблона.