Программирование >>  Синтаксис инициирования исключений 

1 ... 40 41 42 [ 43 ] 44 45 46 ... 82


void Ro11back() Вернуться к самому старому образу

Type* old = history.PopO; Type* oldere = NULL;

if (old != NULL) { Хотя бы один раз

while ((older = history.PopO) != NULL) { delete old; old = older;

delete current; current = old;

Type* operator->() const { return current; }

Хранение отдельного стека в каждом указателе оправданно для транзакций, в которых участвует небольшое количество объектов. Но если одной транзакции приходится отслеживать множество обновляемых объектов, кучу мелких стеков лучше объединить в один большой. Мы сделаем это позднее, когда речь пойдет о транзакциях.

Образы автоматических объектов

Концепцию образа можно немного обобщить, чтобы она распространялась не только на объекты, созданные оператором new и обслуживаемые *-указателями, но и автоматические объекты. Автоматическими считаются стековые объекты, а также переменные и компоненты базовых классов вмещающего объекта независимо от того, выделялась память под вмещающий объект динамически или нет.

template <c1ass Type> class AutoImage { private:

Type current;

Type image;

bool have image; Истина, если образ существует public:

AutoImage() : have image(fa1se) {} AutoImage(const AutoImage<Type>& ai)

: current(ai.current), image(), have image(fa1se) {} AutoImage<Type>& operator=(const AutoImage<Type>& ip)

if (this != &ip) {

current = ip.current; have image = false;

return *this;

AutoImage<Type>& operator=(const Type& t)

current = t;



return *this;

operator Type&() { return current; } void Snapshot()

image = current; have image = true;

void Commit() { have image = false; } void Ro11back()

current = image; have image = false;

bool HaveImage() { return have image; }

Этот шаблон работает со всеми классами, которые удовлетворяют двум условиям:

1 . Тип, используемый в качестве параметра, имеет конструктор без аргументов. Он используется в конструкторе AutoImage для инициализации current и image.

2. Тип, используемый в качестве параметра, допускает присваивание с помощью оператора = по умолчанию, предоставленного компилятором, или перегруженного варианта для данного типа. Используется в функциях Shapshot() и Ro11back().

Все встроенные типы (такие как int и double) удовлетворяют этим условиям. Подходят и другие классы, имеющие конструктор без аргументов и рабочий оператор =. Чем дольше я имею дело с C++, тем чаще мне кажется, что нарушение этих требований - проявление злостного непрофессионализма, за которое следует наказывать парой лет каторжного программирования на BASIC. Заодно я бы издал закон о том, чтобы конструкторы копий всегда работали так, как им положено.

Конструктор копий AutoImage следует примеру ImagePtr и ImageStackPtr - он использует конструктор без аргументов для создания фиктивного объекта image и присваивает have image значение false. Оператор = делает то же самое, однако в нем не удается найти удобный способ уничтожить объект переменной image. Мы выбираем меньшее из двух зол - объект остается без изменений и попросту игнорируется, поскольку переменная have image равна false. Если вас это не устраивает и вы действительно хотите оставить объект image неинициализированным до тех пор, пока в нем не появится настоящий образ, и уничтожить его после присвоения false переменной have image, имеются два возможных решения:

1 . Изменить тип image с Type на Type* и выделять для него память оператором new. Это увеличит накладные расходы по сравнению с автоматическими объектами, однако вы сможете в полной мере контролировать процесс создания и уничтожения.

2. Воспользоваться идиомой виртуальных конструкторов из главы 1 3. Не вдаваясь в подробности, скажу, что это позволит вам объявить image чем-то приятным для глаза - например, unsigned char image(sizeof Type) - нежели вызывать конструктор и деструктор Type вручную. Компиляторы С++ недолюбливают подобные фокусы, поэтому, прежде чем пускаться на авантюры, внимательно прочитайте главу 1 3.

Если AutoImage будет использоваться только для структур или классов, добавьте оператор ->: Type* operator->() { return &current; }

Обратите внимание: в отличие от предыдущих версий -> этот оператор не может быть константной функцией, поскольку current находится внутри *this и мы не можем гарантировать, что -> не будет использоваться для обращений к неконстантным функциям current.



Следующий класс демонстрирует возможное использование этого шаблона. Вмещающему объекту Foo незачем создавать свой образ, как в предыдущих указателях на объекты, поскольку все его переменные способны поддерживать свои образы по отдельности.

class Foo { private:

AutoImage<int> some integer;

AutoImage<Bar> bar; public:

void Ro11back()

some i nteger.Rol 1back(); bar.Ro11back();

void Commit()

some i nteger.Commit(); bar.Commit();

void Snapshot()

some integer.Snapshot(); bar.Snapshot();

int ProvideInt() const { return some integer; } void ChanheInt(int new va1ue)

if (!some integer.HaveImage())

some i nteger.Snapshot(); int&(some integer) = new va1ue;

const Bar& ProvideBar() const { return bar; } Bar& UpdateBar()

if (!bar.HaveImage())

bar.Shapshot(); return Bar&(bar);

Предполагается, что Bar соответствует необходимым условиям. Последние четыре функции перед тем, как обновлять переменную, создают моментальный снимок объекта. Для int получение копии по определению является константным по отношению к копируемой переменной. При вызове функции, изменяющей значение переменной, настает время делать снимок. Для работы с другой переменной, bar, предоставляется как константная, так и неконстантная функция. Конечно, хотелось бы просто перегрузить функцию ProvideBar(), чтобы одна перегруженная версия возвращала const Bar&, а другая - неконстантный Bar&, но тогда их сигнатуры будут совпадать. Помните: две функции не могут иметь одинаковые имена и аргументы и отличаться только типом возвращаемого значения. Я никогда не понимал этого ограничения С++, которое запрещает создавать константную и неконстантную версию оператора ->:

const Type* operator->() const; Снимок не создается

Type* operator->() const; Создает снимок



1 ... 40 41 42 [ 43 ] 44 45 46 ... 82

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