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

ОГЛАВЛЕНИЕ


8.3.3 Реализация списка

Реализация функций slist_base очевидна. Единственная трудность связана с обработкой ошибок. Например, что делать если пользователь с помощью функции get() пытается взять элемент из пустого списка. Подобные ситуации разбираются в функции обработки ошибок slist_handler(). Более развитый метод, рассчитанный на особые ситуации, будет обсуждаться в главе 9.

Приведем полное описание класса slist_base:

          class slist_base {
             slink* last;  // last->next является началом списка
          public:
             void insert(slink* a);  // добавить в начало списка
             void append(slink* a);  // добавить в конец списка
             slink* get();           // удалить и возвратить
                                     // начало списка
             void clear() { last = 0; }

             slist_base() { last = 0; }
             slist_base(slink* a) { last = a->next = a; }

             friend class slist_base_iter;
           };
Чтобы упростить реализацию обеих функций insert и append, хранится указатель на последний элемент замкнутого списка:
           void slist_base_insert(slink* a) // добавить в начало списка
           {
             if (last)
                a->next = last->next;
             else
                last = a;
             last->next = a;
           }
Заметьте, что last->next - первый элемент списка.
           void slist_base::append(slink* a) // добавить в конец списка
           {
             if (last) {
                a->next = last->next;
                last = last->next = a;
             }
             else
                last = a->next = a;
           }

          slist* slist_base::get() // удалить и возвратить начало списка
          {
            if (last == 0)
               slist_handler("нельзя взять из пустого списка");
            slink* f = last->next;
            if (f== last)
               last = 0;
            else
               last->next = f->next;
            return f;
          }
Возможно более гибкое решение, когда slist_handler - указатель на функцию, а не сама функция. Тогда вызов
          slist_handler("нельзя взять из пустого списка");
будет задаваться так
          (*slist_handler)(" нельзя взять из пустого списка");
Как мы уже делали для функции new_handler ($$3.2.6), полезно завести функцию, которая поможет пользователю создавать свои обработчики ошибок:
          typedef void (*PFV)(const char*);

          PFV set_slist_handler(PFV a)
          {
            PFV old = slist_handler;
            slist_handler = a;
            return old;
          }

          PFV slist_handler = &default_slist_handler;
Особые ситуации, которые обсуждаются в главе 9, не только дают альтернативный способ обработки ошибок, но и способ реализации slist_handler.