Читаем Программирование. Принципы и практика использования C++ Исправленное издание полностью

                        // если свободных объектов нет,

                        // возвращаем 0

 void free(T*);         // возвращаем объект типа T, взятый

                        // из пула с помощью функции get

 int available const; // количество свободных объектов типа T

private:

 // место для T[N] и данные, позволяющие определить, какие объекты

 // извлечены из пула, а какие нет (например, список свободных

 // объектов)

};

Каждый объект класса Pool характеризуется типом элементов и максимальным количеством объектов. Его можно использовать примерно так, как показано ниже.

Pool sb_pool;

Pool indicator_pool;

Small_buffer* p = sb_pool.get;

// ...

sb_pool.free(p);

Гарантировать, что пул никогда не исчерпается, — задача программиста. Точный смысл слова “гарантировать” зависит от приложения. В некоторых системах программист должен написать специальный код, например функцию get, которая никогда не будет вызываться, если объектов в пуле больше нет. В других системах программист может проверить результат работы функции get и сделать какие-то корректировки, если результат равен нулю. Характерным примером второго подхода является телефонная система, разработанная для одновременной обработки более 100 тыс. звонков. Для каждого звонка выделяется некий ресурс, например буфер номеронабирателя. Если система исчерпывает количество номеронабирателей (например, функция dial_buffer_pool.get возвращает 0), то она запрещает создавать новые соединения (и может прервать несколько существующих соединений, для того чтобы освободить память). В этом случае потенциальный абонент может вновь попытаться установить соединение чуть позднее.

Естественно, наш шаблонный класс Pool представляет собой всего лишь один из вариантов общей идеи о пуле. Например, если ограничения на использование памяти не такие строгие, можем определить пулы, в которых количество элементов определяется конструктором, и даже пулы, количество элементов в которых может впоследствии изменяться, если нам потребуется больше объектов, чем было указано вначале.

<p id="AutBody_Root490"><strong>25.3.4. Пример стека</strong></p>

Стек — это структура данных, из которой можно брать порции памяти и освобождать последнюю занятую порцию. Используя темно-серый цвет для размещенного объекта и светло-серый для места, готового для размещения объекта, мы можем проиллюстрировать пул следующим образом.

Как показано на рисунке, этот стек “растет” вправо. Стек объектов можно было бы определить как пул.

template class Stack { // стек объектов типа T

 // ...

};

Однако в большинстве систем необходимо выделять память для объектов разных размеров. В стеке это можно сделать, а в пуле нет, поэтому мы покажем определение стека, из которого можно брать “сырую” память для объектов, имеющих разные размеры.

templateclass Stack { // стек из N байтов

public:

  Stack;               // создает стек из N байтов

  void* get(int n);      // выделяет n байтов из стека;

                         // если свободной памяти нет,

                         // возвращает 0

  void free;           // возвращает последнее значение,

                         // возвращенное функцией get

  int available const; // количество доступных байтов

private:

  // память для char[N] и данные, позволяющие определить, какие

  // объекты извлечены из стека, а какие нет (например,

  // указатель на вершину)

};

Поскольку функция get возвращает указатель void*, ссылающийся на требуемое количество байтов, мы должны конвертировать эту память в тип, требуемый для наших объектов. Этот стек можно использовать, например, так.

Stack<50*1024> my_free_store;    // 50K памяти используется как стек

void* pv1 = my_free_store.get(1024);

int* buffer = static_cast(pv1);

void* pv2 = my_free_store.get(sizeof(Connection));

Connection* pconn = new(pv2) Connection(incoming,outgoing,buffer);

Перейти на страницу:
Нет соединения с сервером, попробуйте зайти чуть позже