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.2 Реализация — Exception

13.2 Реализация — Exception

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

Exception — класс, который обеспечивает допускающую вложения обработку исключений. Объекты Exception должны удаляться порядке, обратном их созданию. Обычно новейший объект представляет обработчик ошибок, который получает управление от вызова cause().

 

// new(Exception())

 

#include <setjmp.h>

 

void cause (int number);           // если установлен, идём в catch()

 

% Class Exception: Object {

    int armed;                     // устанавливается catch()

    jmp_buf label;                 // используется catch()

%

    void * catchException (_self);

%}

 

new(Exception()) создаёт объект исключения, который вталкивается в скрытый стек, хранящий все такие объекты:

 

#include "List.h"

 

static void * stack;

 

% Exception ctor {

    void * self = super_ctor(Exception(), _self, app);

 

    if (! stack)

        stack = new(List(), 10);

    addLast(stack, self);

    return self;

}

 

Для реализации стека исключений мы используем объект List из раздела 7.7.

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

 

% Exception dtor {

    void * top;

%casts

    assert(stack);

    top = takeLast(stack);

    assert(top == self);

    return super_dtor(Exception(), self);

}

 

Исключение создаётся вызовом cause() с ненулевым аргументом, кодом исключения. Если возможно, cause() выполнит longjmp() к объекту исключения наверху стека, то есть к самому последнему созданному такому объекту. Обратите внимание на то, что cause() может вернуться в место вызова, а может и нет.

 

void cause (int number) {

    unsigned cnt;

 

    if (number && stack && (cnt = count(stack))) {

        void * top = lookAt(stack, cnt-1);

        struct Exception * e = cast(Exception(), top);

 

        if (e -> armed)

            longjmp(e -> label, number);

    }

}

 

cause() является функцией, не методом. Однако, она реализована как часть реализации Exception и действительно имеет доступ к внутренним данным этого класса. Такая функция часто упоминается как дружественная классу.

cause() принимает много мер предосторожности: параметр не должен быть нулём; должен существовать стек исключений и он должен содержать объекты, а объект наверху стека должен быть исключением; и наконец, объект исключения должен быть готов принять исключение. Если какая-либо проверка терпит неудачу, cause() возвращается и вызвавший её метод должен справиться с ситуацией.

Прежде, чем объект исключения сможет использоваться, он должен быть снаряжён, то есть информация jmp_buf должна быть сохранена с помощью setjmp() до того, как объект будет использоваться cause(). Создание и настройка объекта это две отдельных операции по нескольким причинам. Объект обычно создаётся с помощью new() и объект — результат этой операции. Объект исключения должен снаряжаться setjmp(), а эта функция вернёт два целочисленных значения: в первый раз ноль, а во второй раз значение для передачи в longjmp(). Трудно представить, как можно было бы объединить эти две операции.

Что ещё более важно, ANSI-C вводит серьёзные ограничения на то, где можно вызывать setjmp(). Это должно быть в значительной степени определено только как выражение и это выражение может использоваться только в качестве оператора или управлять оператором цикла или выбора. Изящным решением для снаряжения объекта исключения является следующий макрос, определенный в Exception.d:

 

#define catch(e) setjmp(catchException(e))

 

catch() используется там, где обычно применялся бы setjmp(), то есть ограничения, налагаемые ANSI-C для setjmp(), могут соблюдаться для catch(). Позже значение, переданное cause(), будет возвращено. Трюк основан на вызове метода catchException(), чтобы предоставить параметр для setjmp():

 

% catchException {

%casts

    self -> armed = 1;

    return self -> label;

}

 

catchException() просто устанавливает .armed и возвращает jmp_buf, чтобы setjmp() могла его проинициализировать. Согласно стандарту ANSI-C, jmp_buf имеет тип "массив", то есть имя jmp_buf представляет собой адрес. Если бы система C ошибочно определила jmp_buf как структуру, мы должны были бы просто возвратить её адрес явным образом. Мы не требуем, чтобы catch() была применена к верхнему элементу на стеке исключений.

 

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