|
Программирование >> Разработка устойчивых систем
1nt Counted::count = 0: III:- Класс Counted содержит статический счетчик созданных объектов и выводит сообщения об их уничтожении Каждый объект Counted снабжается идентификатором char*, чтобы за ним было удобнее следить. Класс CountedVector объявлен производным от vector<Counted*>. В конструкторе он создает несколько объектов Counted и передает каждому из них заданный идентификатор char*. Класс CountedVector существенно упрощает тестирование, о чем наглядно свидетельствует следующий пример: : C06:ForEach.cpp Использование алгоритма STL for each() {L} Counted #1nclude <algorithm> #include <1ostreani> #include Counted.h using namespace std: Объект функции: tempiate<cl ass T> class Delete! { public: void operatorOd* x) { delete x: } Шаблонная функция: template <class T> void wiped* x) { delete x: } int mainO { CountedVector B( two ): for each(B.begi n(),В.endO.DeleteT<Counted>()): CountedVector C( three ): for each(C.begin(). C.endO, wipe<Counted>): } III:- Поскольку вызов delete для всех указателей в контейнере требуется достаточно часто, почему бы не создать для этой цели алгоритм? За основу можно взять transform (). Преимущество transform() перед for each() заключается в том, что transform() присваивает результат вызова объекта функции элементу приемного интервала, который может совпадать с исходным интервалом. В последнем случае выполняется преобразование исходного интервала, так как каждый элемент заменяется новым значением. В данном случае этот подход особенно уместен, потому что после вызова delete для указателя будет разумно присвоить ему безопасное нулевое значение. Алгоритм transform() позволяет легко решить эту задачу: : СОб:Transform.срр Использование алгоритма STL transformO {L} Counted #include <iostream> #include <vector> #include <algorithm> #include Counted.h using namespace std: Копирующий конструктор и оператор присваивания отсутствуют в классе, поскольку они не задействованы в нашем примере. tempiate<class Т> Т* deletePd* х) { delete х: return 0: } tempiate<class T> struct Deleter { T* operatorO(T* x) { delete x: return 0: } int mainO { CountedVector cvCone ): transformCcv.beginO. cv.endO. cv.beginO, deleteP<Counted>): CountedVector cv2( two ): transform(cv2.begin(). cv2.endO, cv2.begin(). Deleter<Counted>()); } III:- В этой программе продемонстрированы оба подхода: использование шаблонной функции и шаблонного объекта функции. После вызова transform() вектор содержит пять нулевых указателей, что позволяет защититься от повторных вызовов delete. Однако вам не удастся вызвать delete для каждого указателя в контейнере без инкапсуляции вызова в функции или объекте. Иначе говоря, речь идет о следующей конструкции: for each(a.begin(). a.endO. ptr fun(operator delete)); Дело в том, что операторная функция operator delete() получает void*, но итератор не является указателем. Впрочем, даже если бы вам удалось заставить компилироваться программу, в итоге получилась бы последовательность вызовов функции освобождения памяти. В отличие от вызова delete для каждого указателя в а, деструкторы вызываться не будут. Обычно это не то, что требуется, поэтому вызовы delete необходимо инкапсулировать. В предыдущем примере с алгоритмом for each() возвращаемое значение алгоритма игнорировалось. Этим возвращаемым значением является функция, переданная for each(). Для обычного указателя на функцию возвращаемое значение особой пользы не приносит, но объект функции может накапливать информацию об объектах, перебираемых в процессе работы for each(), в своей внутренней переменной. Для примера рассмотрим простую модель складского учета. Каждый объект Inventory содержит название товара (в нашем примере он представляется одиночным символом), количество единиц на складе и цену одной единицы: ; СОб;Inventory.h #ifndef INVENTORYJ #define INVENTORYJ #i nclude <iostream> linclude <cstdlib> using std::srand: class Inventory { char item; int quantity; int value: public: Inventory(char it. int quant, int val) : itemdt), quantlty(quant). value(val) {} Сгенерированный оператор присваивания и копирующий конструктор подходят, char getltemO const { return Item; } int getQuantityO const { return quantity; } void setQuantity(int q) { quantity = q; } int getValueO const { return value; } void setValue(int val) { value = val; } friend std: :ostream& operator ( std::ostream& os. const InventoryS inv) { return os inv.item : quantity inv.quantity . value inv.value; Генератор: struct InvenGen { Inventory operatorOO { static char с = a: int q = randO % 100: int v = randO % 500; return Inventory(С++, q. v); #endif INVENTORYJ /:- Функции класса возвращают название товара, а также возвращают и задают количество и цену. Оператор выводит объект Inventory в поток ostream. Генератор создает объекты с последовательно сгенерированными названиями, случайными количествами и ценами. Чтобы подсчитать общее количество единиц товара и общую цену, мы создаем для for each() объект функции, в переменных которого будет накапливаться нужная информация: : C06:CalcInventory.cpp Пример использования for each() linclude <algorithm> linclude <ctime> linclude <vector> linclude Inventory.h linclude PrintSequence.h using namespace std: Вычисление сводной информации: class InvAccum { int quantity; int value; public: InvAccumO : quantity(O). value(O) {} void operatorO (const Inventory?, inv) { quantity += inv.getQuantityO; value += inv.getQuantityO * inv.getValueO: friend ostreamS operator (ostream& os, const InvAccumS ia) { return OS total quantity: ia.quantity
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0.001
При копировании материалов приветствуются ссылки. |