|
Программирование >> Синтаксис инициирования исключений
private: SafeSet<Lock>* locks; void AddLock(Lock*); Включить блокировку в транзакцию public: ~Transaction(); void Commit(); Закрепить все образы void Ro11back(); Отменить все образы bool OwnsLock(Lock*); Истина, если блокировка принадлежит транзакции Класс Transaction поддерживает коллекцию блокировок с помощью гипотетического шаблона Collection. Функция RegisterLock() включена в базовый класс Lock и потому может обратиться к закрытой функции AddLock() класса Transaction. Дружба не наследуется, поэтому объявление другом класса Lock не делает друзьями его производные классы. Реализации выглядят довольно просто. void Transaction::AddLock(Lock* lock) *1ocks += lock; Использует перегрузку += для коллекции void Transaction::Commit() SafeSetIterator<Lock>* iter = 1ocks->Iterator(); while (iter->More()) iter->Next()->Commit(); delete iter; void Transaction::Ro11back() SafeSetIterator<Lock>* iter = 1ocks->Iterator(); while (iter->More()) iter->Next()->Ro11back(); delete iter; bool Transaction::OwnsLock(Lock* lock) return *1ocks >= lock; Предполагается, что шаблон Collection содержит функцию De1eteAl1() для удаления всех объектов; что перегруженный оператор += (операторная функция operator+=(Type*) ) включает элемент в коллекцию; что перегруженный оператор >= определяет принадлежность к коллекции, а функция Iterator() возвращает вложенный итератор. Это обобщенные условия; используйте те, которые действуют в вашем случае. Класс ConstPtr Классы, производные от Lock, должны ссылаться на нечто близкое к указателям, доступным только для чтения, с которыми на страницах книги вы уже познакомились. template <c1ass Type> class LockPtr; Ссылка вперед на класс, производный от Lock template <c1ass Type> class ConstPtr { friend class LockPtr<Type>; private: Type* o1d image; Образ перед транзакцией LockPtr<Type>* lock; Текущая блокировка, если она есть ~ConstPtr() { delete o1d image; } ConstPtr<Type>& operator=(const ConstPtr<Type>& cp) { return *this; } Присваивание не разрешается public: ConstPtr() : o1d image(NULL), lock(NULL) {} ConstPtr(const ConstPtr<Type>& cp) : o1d image(new Type(*(cp.o1d image))), lock(NULL) {} const Type* operator->() const { return o1d image; } LockPtr<Type>& Lock(Transaction* t); template <c1ass Type> LockPtr<Type>& ConstPtr<Type>::Lock(Transaction* t) if (lock != NULL && !t->OwnsLock(1ock)) Конфликт - уже имеется другой владелец else { lock = new LockPtr<Type>(t, this); return *1ock; Новый объект ConstPtr можно сконструировать на базе старого (хотя новый создается без блокировки), однако нам придется внести изменения для присваивания, которое разрешено только для LockPtr , но не для ConstPtr . Для этой цели мы определяем фиктивный оператор = и делаем его закрытым, чтобы до него никто не добрался. Поскольку указатель является ведущим, его удаление приводит и к удалению указываемого объекта (самое радикальное изменение, которое только можно представить). По этой причине конструктор также объявлен закрытым, чтобы никто не попытался удалить ConstPtr . Конфликт в функции Lock можно обработать разными способами: Инициировать исключение. Изменить интерфейс и возвращать вместе с блокировкой флаг, показывающий, успешно ли прошла блокировка. Возвращать LockPtr<Type>* со значением NULL, свидетельствующем о неудачной блокировке. Возвращать конфликтную блокировку с перегруженным оператором ! , с помощью которого можно проверить правильность блокировки. Предоставить отдельную функцию CanLock(Transaction*) , которая возвращает логическое значение. Выбор зависит от стиля. Вариант с исключением не так уж очевиден; неудача при блокировке представляет собой вполне разумный исход. Класс LockPtr Ага! Мы подошли к центральной идее всей концепции - указателям, которые разрешают обновление указываемого объекта. Предтранзакционный (предназначенный для отмены) образ хранится в ConstPtr, а текущий обновленный образ доступен только через LockPtr. Класс LockPtr содержит уже знакомые функции Ro11back() и Commit(). В функции Snapshot() нет необходимости, поскольку LockPtr при необходимости создает образы в операторе ->. template <c1ass Type> class LockPtr : public Lock { friend class ConstPtr<Type>; private: ConstPtr<Type>* master ptr; Type* new image; Transaction* transaction; LockPtr(Transaction* t, ConstPtr<Type>* cp); virtual ~LockPtr(); virtual void Ro11back(); virtual void Commit(); public: Type* operator->() const { return new image; } template <c1ass Type> LockPtr<Type>::LockPtr(Transaction* t, ConstPtr<Type>* cp) : transaction(t), master ptr(cp), new image(new Type(*(cp->o1d image))) template <c1ass Type> LockPtr<Type>::~LockPtr() В сущности происходит откат delete new image; Отказаться от изменений master ptr->1ock = NULL; Оставить ConstPtr template <c1ass Type> void LockPtr<Type>::Ro11back() delete new image; new image = new Type(*(master ptr->o1d image)); template <c1ass Type> void LockPtr<Type>::Commit() delete master ptr->o1d image; master ptr->o1d image = new image; Переместить в master ptr new image = new Type(*new image); Нужна новая копия Деструктор объявлен закрытым, чтобы никто не мог напрямую удалить LockPtr. Вместо этого транзакция-владелец должна сделать это через базовый класс Lock. Функции Ro11back() и Commit () объявлены виртуальными, чтобы с их помощью можно было решать задачи, относящиеся к
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |