|
Программирование >> Разработка устойчивых систем
деления ресурсов будут должным образом уничтожены в процессе раскрутки стека. Эта методика называется получением ресурсов при инициализации (Resource Acquisition Is Initialization, RATI), поскольку управление ресурсом (выделение и освобождение) совмещается с основными точками жизненного цикла объекта. Ниже показано, как эта задача решается за счет применения шаблонов в предыдущем примере: : СО1:Wrapped.срр Безопасные, атомарные указатели #1nclude <iostream> #1nclude <cstddef> using namespace std: Упрощение. В вашем случае могут использоваться другие аргументы, tempiate<class Т. 1nt sz = 1> class PWrap { T* ptr: public: class RangeError {}: класс исключения PWrapO { ptr = new T[sz]: cout PWrap constructor endl: -PWrapO { delete [] ptr: cout PWrap destructor endl: T& operator[](int i) throw(RangeError) { if(i >= 0 && i < sz) return ptr[i]; throw RangeErrorO; class Cat { public: CatO { cout CatO endl: } -CatO { cout -CatO endl; } void gO {} class Dog { public: void* operator new[](size t) { cout Allocating a Dog endl; throw 47; void operator delete[](void* p) { cout Deallocating a Dog endl; ;:operator delete[](p): class UseResources { PWrap<Cat. 3> cats: PWrap<Dog> dog: public: UseResourcesO { cout UseResourcesO endl; -UseResourcesO { В стандартную библиотеку С++ входит класс исключения std::out of range, предназначенный именно для таких ситуаций. cout -UseResourcesO endl: void fO { cats[l].g(): } int mainO { try { UseResources ur: } catch(int) { cout inside handler endl: } catchO .) { cout inside catch(...) endl: } III:- В новой версии шаблоны используются как оболочки для указателей и их инкапсуляции в объекты. Конструкторы этих объектов вызываются до основного кода конструктора \}seRs,o\ixzes и для любого конструктора, завершившегося прежде возникновения ис1слючения, в процессе раскрутки стека будет вызван соответствующий деструктор. Шаблон PWrap демонстрирует более типичное применение исю1ючений: в нем определяется вложенный класс RangeError, который используется в операторной функции operator[] при выходе аргумента из интервала допустимых значений. Поскольку функция operator[] возвращает ссылку, она не может вернуть ноль (нулевых ссылок не существует). Такая ситуация действительно является исключительной - в текущем контексте нельзя решить, что делать дальше, и возвращать недостоверное значение тоже нельзя. В приведенном примере используется простейший класс исключения RangeError. Предполагается, что вся необходимая информация содержится в имени класса, хотя при необходимости в него можно включить переменную со значением индекса. На этот раз результат выглядит так: Cat О Cat О Cat О PWrap constructor allocating а Dog -Cat О -Cat О -Cat О PWrap destructor inside handler И снова при выделении памяти для Dog происходит исключение. Однако на этот раз массив объектов Cat уничтожается так, как положено, и утечки памяти не возникает. auto ptr в типичной программе С++ динамическая память является наиболее часто используемым ресурсом. По этой причине в стандарте предусмотрена КАП-оболочка для указателей на память в щче обеспечивающая автоматическое освобождение памя- ти. У шаблонного класса auto ptr, определяемого в заголовочном файле <memory>, имеется конструктор, получающий указатель на тип параметра (то есть тип, непосредственно используемый в программе). Шаблон auto ptr также перегружает операторы * и -> и выполняет соответствующие операции с исходным указателем, инкапсулированным в объекте auto ptr. Таким образом, с объектом auto ptr можно работать так, как если бы он был обычным указателем. Вот как это делается: : C01:Auto ptr.cpp Демонстрация RAII-природы класса auto ptr linclude <memory> #1nc1ude <1ostream> #1nclude <cstddef> using namespace std; class TraceHeap { int i; public: static void* operator new(size t siz) { void* p = ::operator new(siz): cout Allocating TraceHeap object on the heap at address p endl; return p; static void operator deleteCvoid* p) { cout Deleting TraceHeap object at address p endl; ::operator delete(p): TraceHeapCint i) : i(i) {} int getVal0 const { return i: int mainO { auto ptr<TraceHeap> pMyObjectCnew TraceHeap(5)): cout pMyObject->get\/al() endl; Выводит 5 } III:- Класс TraceHeap перегружает операторы new и delete, чтобы они выводили полную информацию о происходящих событиях. Как и в любом другом шаблоне, фактический тип указывается в параметре шаблона. Однако мы не используем запись TraceHeap* - объект auto ptr уже знает, что в нем будет храниться указатель на ваш тип. Вторая строка main() позволяет убедиться в том, что в функции operator->() класса auto ptr происходит косвенное обращение к исходному низкоуровневому указателю. Еще важнее другое: хотя исходный указатель не удаляется в программе, деструктор pMyObject удаляет его в процессе раскрутки стека, как видно из следующего вывода: Allocating TraceHeap object on the heap at address 8930040 5 Deleting Traceheap object at address 8930040 Шаблон auto ptr также удобен при работе с указателями на переменные классов. Поскольку объекты классов, хранимые по значению, всегда уничтожаются, переменные типа auto ptr при уничтожении внешнего объекта всегда удаляют объект, связанный с хранящимся в них низкоуровневым указателем.
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0.001
При копировании материалов приветствуются ссылки. |