Программирование >>  Разработка устойчивых систем 

1 ... 3 4 5 [ 6 ] 7 8 9 ... 196


деления ресурсов будут должным образом уничтожены в процессе раскрутки стека. Эта методика называется получением ресурсов при инициализации (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 при уничтожении внешнего объекта всегда удаляют объект, связанный с хранящимся в них низкоуровневым указателем.



1 ... 3 4 5 [ 6 ] 7 8 9 ... 196

© 2006 - 2024 pmbk.ru. Генерация страницы: 0.001
При копировании материалов приветствуются ссылки.
Яндекс.Метрика