The website "dmilvdv.narod.ru." is not registered with uCoz.
If you are absolutely sure your website must be here,
please contact our Support Team.
If you were searching for something on the Internet and ended up here, try again:

About uCoz web-service

Community

Legal information

13.3 Примеры

13.3 Примеры

Предыдущая  Содержание  Следующая V*D*V

В нашем калькуляторе мы можем заменить явный вызов setjmp() в parse.c на объект исключения:

 

int main (void) {

    volatile int errors = 0;

    char buf [BUFSIZ];

    void * retry = new(Exception());

    ...

    if (catch(retry)) {

        ++ errors;

        reclaim(Node(), delete);

    }

    while (gets(buf))

        ...

 

Порождение исключения перезапустит основной цикл. error() изменяется таким образом, что она завершается порождая исключение:

 

void error (const char * fmt, ...) {

    va_list ap;

 

    va_start(ap, fmt);

    vfprintf(stderr, fmt, ap), putc(’\n’, stderr);

    va_end(ap);

    cause(1);

    assert(0);

}

 

error() вызывается при любой ошибке, обнаруженной в калькуляторе. Она распечатывает сообщение об ошибке и порождает исключение, которое обычно будет непосредственно перезапускать основной цикл. Однако, когда Symtab выполняет свой метод load, он добавляет свой собственный обработчик исключений:

 

% Symtab load {

    FILE * fp;

    void * in;

    void * cleanup;

    ...

    if (! (fp = fopen(fnm, "r")))

        return EOF;

 

    cleanup = new(Exception());

    if (catch(cleanup)) {

        fclose(fp);

        delete(cleanup);

        cause(1);

        assert(0);

    }

    while (in = retrieve(fp))

        ...

    fclose(fp);

    delete(cleanup);

    return result;

}

 

Мы видели в разделе 12.5, что есть проблема, если load() работает с выражением и если getsymbol() не может подключить имя к соответствующему символу в таблице:

 

else if (lex(result) != token)

    error("%s: need a %s, got a %s",

            buf, nameOf(class), nameOf(classOf(result)));

 

Всё, что теперь требуется сделать, это вызвать error() для распечатки сообщения. error() порождает исключение, которое отлавливается в данный момент через объект исключения cleanup в load(). В этом обработчике известно, что поток fp должен быть закрыт перед тем, как может быть завершена load(). Когда cleanup удалён и порождается другое исключение, управление наконец достигает обычного обработчика исключений, установленного с помощью retry в main(), где лишние узлы удаляются и перезапускается основной цикл.

Этот пример демонстрирует, что лучше разрабатывать cause() как функцию, которая лишь передаёт код исключения. error() можно вызывать из различных защищённых контекстов и она автоматически вернётся к надлежащему обработчику исключений. Удаляя соответствующий объект исключения и вызывая cause() снова мы можем вызвать срабатывание всех обработчиков вверх по цепочке.

Обработка исключений пахнет goto со всей его дурной славой. Следующий ужасный пример для создания вывода использует switch и два объекта исключения

 

$ except

caused -1

caused 1

caused 2

caused 3

caused 4

 

Вот этот код; дополнительные очки присуждаются, если вы проследите его с карандашом...

 

int main () {

    void * a = new(Exception()), * b = new(Exception());

 

    cause(-1); puts("caused -1");

 

    switch (catch(a)) {

    case 0:

        switch (catch(b)) {

        case 0:

            cause(1); assert(0);

        case 1:

            puts("caused 1");

            cause(2); assert(0);

        case 2:

            puts("caused 2");

            delete(b);

            cause(3); assert(0);

        default:

            assert(0);

        }

    case 3:

        puts("caused 3");

        delete(a);

        cause(4);

        break;

    default:

        assert(0);

    }

    puts("caused 4");

    return 0;

}

 

Этот код, конечно, ужасен и непонятен. Однако, если, чтобы создать набор операций, показанный в начале этой главы, используется обработка исключений

 

OOC_Strategy_1

 

мы все ещё поддерживаем для управляющих структур парадигму один вход, один выход, которая является основой структурного программирования. Класс Exception обеспечивает чистый, инкапсулированный механизм для вложения обработчиков исключений, и таким образом позволяет вложить одно защищённое опасное действие в другое.

 

Предыдущая  Содержание  Следующая