2.6 Другая реализация — Atom

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

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

 

struct String {

    const void * class;   /* должен быть первым */

    char * text;

    struct String * next;

    unsigned count;

};

 

static struct String * ring; /* всех строк */

 

static void * String_clone (const void * _self) {

    struct String * self = (void *) _self;

 

    ++ self -> count;

    return self;

}

 

Наш круговой список всех атомов запоминается в ring, увеличиваясь через поле .next компонента, и поддерживается с помощью конструктора и деструктора строки. Перед тем как конструктор сохраняет текст, он сначала просматривает список, чтобы увидеть, был ли уже сохранён этот текст. В начало String_ctor() вставлен следующий код:

 

if (ring) {

    struct String * p = ring;

    do

        if (strcmp(p -> text, text) == 0) {

            ++ p -> count;

            free(self);

            return p;

    }

    while ((p = p -> next) != ring);

}

else

    ring = self;

 

self -> next = ring -> next, ring -> next = self;

self -> count = 1;

 

Если мы находим подходящий атом, то увеличиваем его счётчик ссылок, освобождаем память новой строки объекта self и вместо неё возвращаем атом p. В противном случае мы вставляем новый объект строки в круговой список и устанавливаем его счётчик ссылок в 1.

Деструктор предотвращает удаление атома до тех пор, пока его счётчик ссылок не уменьшится до нуля. В начало String_dtor() вставлен следующий код:

 

if (-- self -> count > 0)

    return 0;

 

assert(ring);

if (ring == self)

    ring = self -> next;

if (ring == self)

    ring = 0;

else {

    struct String * p = ring;

 

    while (p -> next != self) {

        p = p -> next;

        assert(p != ring);

    }

    p -> next = self -> next;

}

 

Если уменьшаемый счётчик ссылок положителен, возвращается нулевой указатель, чтобы delete() оставила наш объект нетронутым. В противном случае мы очищаем маркер кругового списка, если наша строка была последней, или убираем строку из списка.

Реализация нашего приложения из раздела 2.4 замечает, что клонированная строка идентична оригиналу и печатает

 

sizeOf(a) == 16

ok

clone?

 

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