Бьерн Страуструп (947334), страница 83
Текст из файла (страница 83)
public:
Pool(unsigned n);
~Pool();
void* alloc();
void free(void* b);
};
inline void* Pool::alloc()
{
if (head==0) grow();
Link* p = head;
head = p->next;
return p;
}
inline void Pool::free(void* b)
{
Link* p = (Link*) b;
p->next = head;
head = p;
}
Приведенные описания логично поместить в заголовочный файл Pool.h.
Следующие определения могут находиться в любом месте программе и
завершают наш пример. Объект Pool должен инициализироваться
конструктором:
Pool::Pool(unsigned sz)
: esize(sz)
{
head = 0;
}
Функция Pool::grow() будет связывать все элементы в список квантов
свободной памяти head, образуя из них новый блок. Определения
остальных функций-членов оставлены в качестве упражнений 5 и 6 в
$$13.11.
void Pool::grow()
{
const int overhead = 12;
const int chunk_size = 8*1024-overhead;
const int nelem = (chunk_size-esize)/esize;
char* start = new char[chunk_size];
char* last = &start[(nelem-1)*esize];
for (char* p = start; p<last; p+=esize)
((Link*)p)->next = ((Link*)p)+1;
((Link*)last)->next = 0;
head = (Link*)start;
}
13.11 Упражнения
1. (*3) Завершите определения функций-членов класса Type_info.
2. (*3) Предложите такую структуру объекта Type_info, чтобы функция
Type_info::get_info() стала лишней, и перепишите с учетом этого
функции-члены Type_info.
3. (*2.5) Насколько наглядно вы сможете записать примеры с Dialog_box,
не используя макроопределения (а также расширения языка)? Насколько
наглядно вам удастся записать их, используя расширения языка?
4. (*4) Исследуйте две широко распространенные библиотеки.
Классифицируйте все библиотечные классы, разбив их на: конкретные
типы, абстрактные типы, узловые классы, управляющие классы и
интерфейсные классы. Используются ли абстрактные узловые классы
и конкретные узловые классы? Можно ли предложить более подходящее
разбиение классов этих библиотек? Используется ли обширный
интерфейс? Какие имеются средства динамической информации о типе
(если они есть)? Какова стратегия управления памятью?
5. (*3) Определите шаблонный вариант класса Pool из $$13.10.3. Пусть
размер выделяемого элемента памяти будет параметром шаблона
типа, а не конструктора.
6. (*2.5) Усовершенствуйте шаблон типа Pool из предыдущего упражнения
так, чтобы некоторые элементы размещались во время работы конструктора.
Сформулируйте в чем будет проблема переносимости, если использовать
Pool с типом элементов char, покажите как ее устранить.
7. (*3) Если ваша версия С++ прямо не поддерживает динамические
запросы о типе, обратитесь к своей основной библиотеке. Реализован
ли там механизм динамических запросов о типе? Если это так,
задайте операции из $$13.5 как надстройку над этим механизмом.
8. (*2.5) Определите такой строковый класс, в котором нет никакого
динамического контроля, и второй производный от него строковый
класс, который только проводит динамический контроль и обращается
к первому. Укажите плюсы и минусы такого решения по сравнению
с решением,в котором делается выборочный динамический контроль,
сравните с подходом, использующим инварианты, как было предложено
в $$12.2.7.1. Насколько можно совмещать эти подходы?
9. (*4) Определите класс Storable как абстрактный базовый класс с
виртуальными функциями writeout() и readin(). Для простоты
допустим, что для задания нужного адресного пространства достаточно
строки символов. С помощью класса Storable реализуйте
обмен объектами с диском. Проверьте его на объектах нескольких
классов по своему усмотрению.
10.(*4) Определите базовый класс Persistent с операциями save()
и nosave(), который будет проверять, что деструктор создал объект
в определенной памяти. Какие еще полезные операции можно предложить?
Проверьте класс Persistent на нескольких классах по своему выбору.
Является ли класс Persistent узловым классом, конкретным или
абстрактным типом? Аргументируйте ответ.
11.(*3) Составьте только описание класса stack, который реализует
стек с помощью операций create() (создать стек), delete()
(уничтожить стек), push() (записать в стек) и pop() (читать из
стека). Используйте только статические члены. Для привязки и
обозначения стеков определите класс id. Гарантируйте, что
пользователь сможет копировать объекты stack::id, но не сможет
работать с ними иным способом. Сравните это определение стека
с классом stack из $$8.2.
12.(*3) Составьте описание класса stack, который является абстрактным
типом ($$13.3). Предложите две различные реализации для интерфейса,
заданного stack. Напишите небольшую программу, работающую с
этими классами. Сравните это решение с классами, определяющими
стек, из предыдущего упражнения и из $$8.2.
13.(*3) Составьте такое описание класса stack, для которого можно
в динамике менять реализацию. Подсказка: "Всякую задачу можно
решить, введя еще одну косвенность".
14.(*3.5) Определите класс Oper, содержащий идентификатор (некоторого
подходящего типа) и операцию (некоторый указатель на функцию).
Определите класс cat_object, содержащий список объектов Oper и
объект типа void*. Задайте в классе cat_object операции:
add_oper(), которая добавляет объект к списку; remove_oper(id),
которая удаляет из списка объект Oper c идентификатором id;
operator() (id,arg), которая вызывает функцию из объекта Oper c
идентификатором id. Реализуйте с помощью класса cat_object
стек объектов Oper. Напишите небольшую программу, работающую
с этими классами.
15.(*3) Определите шаблон типа Object, служащий базовым классом
для cat_object. С помощью Object реализуйте стек для объектов
класса String. Напишите небольшую программу, использующую этот
шаблон типа.
16.(*3) Определите вариант класса Object под именем Class, в котором
объекты с одинаковым идентификатором имеют общий список операций.
Напишите небольшую программу, использующую этот шаблон типа.
17.(*3) Определите шаблон типа Stack, который задает традиционный
и надежный интерфейс со стеком, реализуемым объектом шаблона
типа Object. Сравните это определение стека с классами, задающими
стек, из предыдущих упражнений. Напишите небольшую программу,
использующую этот шаблон типа.
Обращений с начала месяца: 136, Last-modified: Fri, 22 Jan 1999 15:04:52 GMT
Начало формы