Материалы книги получены с http://www.itlibitum.ru/
Создание и уничтожение объектов
Пора заполнить кое-какие пробелы. Раз уж наши транзакции достаточно сложны, чтобы для них была оправдана вся эта возня, они наверняка будут создавать или уничтожать объекты. Операции создания и уничтожения также должны быть отменяемыми. Если объект создавался, операция отмены должна его уничтожать, а если уничтожался - возвращать его из мертвых. Для этого придется внести изменения как в класс ConstPtr, так и в класс LockPtr. Мы уже сделали первый шаг в этом направлении, объявив деструктор ConstPtr закрытым, чтобы им могли воспользоваться только ConstPtr или его друзья. Давайте разберемся с оставшимися проблемами.
Изменения в классе ConstPtr
Несомненно, создание указываемого объекта представляет собой изменение и потому должно осуществляться через LockPtr. Но для того чтобы получить LockPtr, мы должны сначала иметь ConstPtr и его функцию Lock(). Следовательно, только что описанный конструктор ConstPtr работать не будет - он создает уникальный объект перед вызовом Lock(). ConstPtr должен находиться в состоянии NULL до тех пор, пока LockPtr не выделит память под объект и не закрепит эти изменения. В ConstPtr необходимо внести следующие изменения:
1. В конструкторе без аргументов присваивать переменной old_image значение NULL.
2. Добавить оператор !, который проверяет, равен ли адрес значению NULL.
3. Инициировать исключение в операторе ->, если адрес равен значению NULL.
4. Либо запретить копирование, либо присвоить копии old_image значение NULL.
Проблема с обычным конструктором копий ConstPtr заключается в том, что он может создать новую копию указываемого объекта, но не позволит отменить ее создание. Ниже приводится новая версия конструктора ConstPtr. Определения функций, не изменившиеся по сравнению с показанной выше упрощенной версией не показаны.
private:
ConstPtr(const ConstPtr&) : old_image(NULL), lock(NULL) {}
public:
ConstPtr() : old_image(NULL), lock(NULL) {}
bool operator!() { return old_image == NULL; }
const Type* operator->() const
{
if (old_image == NULL)
// Исключение
return old_image;
}
Изменения в классе LockPtr
Отныне LockPtr предстоит выполнять намного больше работы:
1. Он должен при необходимости создавать указываемый объект по требованию. Для этого в него будет добавлена функция Make().
2. Оператор -> должен инициировать исключение, если адрес равен NULL.
Ниже приведены определения толькоизменившихся функций.
// В объявлении LockPtr
public:
void Make(); // Создать новый указываемый объект
void Destroy(); // Уничтожить указываемый объект
// Изменившиеся определения
template <class Type>
LockPtr<Type>::LockPtr(Transaction* t, ConstPtr<Type>* cp)
: transaction(t), master_ptr(cp),
new_image(cp->old_image != NULL ? new Type(*(cp->old_image)) : NULL)
{
}
template <class Type>
void LockPtr<Type>::Commit()
{
delete master_ptr->old_image;
master_ptr->old_image = new_image;
if (new_image != NULL)
new_image = new Type(*new_image);
}
template <class Type>
Type* LockPtr<Type>::operator->() const
{
if (new_image == NULL)
// исключение
return new_image;
}
template <class Type>
void LockPtr<Type>::Make()
{
delete new_image; // Если new_image не равен NULL
new_image = new Type; // Новый пустой объект
}
template <class Type>
void LockPtr<Type>::Destroy()
{
delete new_image;
new_image = NULL;
}
Функция Make() соблюдает семантику присваивания, что позволяет вызвать ее для существующего указываемого объекта. При этом объект, на который в данный момент ссылается LockPtr, уничтожается и заменяется новым пустым объектом.
Назад Содержание Далее
|