2.6 Другая реализация — Atom |
Предыдущая Содержание Следующая |
Для иллюстрации того, что можно сделать с помощью интерфейса конструктора и деструктора мы реализуем атомы. Атом является уникальным строковым объектом; если два атома содержат одни и те же строки, они идентичны. Атомы очень дёшевы для сравнения: 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?
|
Предыдущая Содержание Следующая |