Регистрация Главная Сообщество
Сообщения за день Справка Регистрация
Навигация
Zhyk.org LIVE! Реклама на Zhyk.org Правила Форума Награды и достижения Доска "почета"

Ответ
 
Опции темы
Старый 05.12.2008, 18:18   #1
Заблокирован
 Старший сержант
Аватар для shagart
 
shagart у всех на слухуshagart у всех на слухуshagart у всех на слухуshagart у всех на слухуshagart у всех на слухуshagart у всех на слухуshagart у всех на слухуshagart у всех на слухуshagart у всех на слухуshagart у всех на слуху
Регистрация: 16.07.2008
Сообщений: 209
Популярность: 1335
Сказал(а) спасибо: 231
Поблагодарили 236 раз(а) в 134 сообщениях
Отправить сообщение для shagart с помощью ICQ Отправить сообщение для shagart с помощью Telegram Отправить сообщение для shagart с помощью Yahoo Отправить сообщение для shagart с помощью Skype™
 
По умолчанию Классы объектов, поддерживающие транзакции. Продолжение

Раз уж взялись, что мешает вставить в наш умный указатель с поддержкой отмены не один, а несколько предыдущих состояний объекта? Ничего. Только чтобы потом несколько раз не переделывать, решим несколько чисто технических моментов:
Какую структуру будем использовать в качестве коллекции состояний ? Можно взять стек, можно кольцевой буфер, а можно и карту (словарь, хэш-таблицу); стек явно проще, зато за кольцевым буфером можно не следить вообще, пусть устаревшие состояния пропадают бесследно (конечно по желанию).
Определимся с семантикой. Смешивать значения и указатели не стоит, верный путь заработать себе геморрой. У меня не оказалось под рукой подходящего стека, и я написал для этого Шага два варианта - один хранит значения, другой - указатели; первый стек сначала казался проще, но использующий его класс указателя оказался ощутимо сложнее по простой причине - функции стека с указателями могут возвращать NULL, а это совсем немало.
Оформим все в виде шаблонов; вообще контейнеры просто просятся быть шаблонами, а smart-указатели несомненно являются контейнерами.

Код ниже, а сейчас пояснения:

Класс CType просто проверочный, чтобы вкладывать в шаблоны; так проще отлаживать шаблон: сначала сделать контейнер-не-шаблон для класса Type, а потом просто приписать сверху объявления строку template<Type>. Шаблон класса ampstack<Type> - шаблон стека указателей; push сохраняет указатель, pop достает верхний указатель, isEmpty проверяет на пустоту, emptyAll очищает.

Шаблон класса MLTrans - наконец тот, который нам нужен. Указатель that хранит текущее значение, Push сохраняет текущее значение, PopOne делает однократную отмену, Rollback отменяет все изменения, до первоначального, Commit удаляет историю.
Код:
// Это маленький класс для проверки
class CType {
	int a;
public:
	void set (int _a){a=_a;};
	int get (void) {return a;};
};
// Шаблон стека
template <class Type>
class ampstack{
private:
	int iTop;  // верх стека
	int iSize; // размер стека
	Type** array; // массив указателей
public:
	// Конструктор-деструктор
	ampstack(int size=10):iTop(0), iSize(size), array(new Type*[size]) {};
	~ampstack()
	{
		for ( int iCounter = 0; iCounter < iTop; iCounter ++)
			if (*(array+iCounter) != NULL) delete *(array+iCounter);
			delete[] array;
		};
	// Управление стеком
	// Направить указатель в стек
	void push (Type* _t){ array[iTop++]=_t;};
	// Вынуть указатель из стека
	Type* pop (void)
	{
		if ( iTop == 0) return NULL;
		else return array[--iTop];
	};
	// Стек пуст?
	int isEmpty  ( void) { return iTop==0;};
	// Очистить стек
	void emptyAll (void)
	{
		for (int iCounter = 0; iCounter < iTop; iCounter ++)
			if (*(array+iCounter) != NULL) delete *(array+iCounter); iTop = 0;
	};
};
// Шаблон класса с многоуровневой отменой
template <class Type>
class MLTrans{
typedef ampstack<Type> stack;
private:
	Type* that; // Текущее значение
	stack history;  // контейнер предыдущих значений
public:
// конструктор-деструктор
	MLTrans(): that(new Type){};
 	~MLTrans (){delete that;};
// Сохранение текущего значения, aналог SAVE TRANSACTION в SQL серверах
	void Push()
	{
		history.push (that); 
		that = new Type(*that);
	};
// удаление промежуточных состояний
	void Commit (){history.emptyAll();};
// Откат на одну позицию; уничтожает текущее значение.
	void PopOne()
	{
		if (!history.isEmpty())
		{
			delete that;
			that = history.pop();
		};
	};
// Откат к началу транзакции.
	void Rollback ()
	{
		Type* old = history.pop();
		Type* older = NULL;
 		if (old != NULL)
		{
			while ((older = history.pop()) != NULL) 
			{
				delete old; 
				old = older;
			}
			delete that; that = old;
 		}
	};
// Переопределенный operator->
	Type* operator->() {return that;};
};
// проверим работу
int main ()
{
	int t;
	MLTrans<CType> a;
	a->set(5);
	t = a->get();
	a.Push();
	a->set(6);
	t = a->get();
	a.Push();
	t = a->get();
	a->set(7);
	t = a->get();
	a.Push();
	t = a->get();
	a->set(9);
	t = a->get();
//  a.Push();
	t = a->get();
	a.PopOne();
	t = a->get();
	a.Rollback();
	t = a->get();
	return 0;
}
  Ответить с цитированием
2 пользователя(ей) сказали cпасибо:
Ivan_32 (05.12.2008), Zhyk (05.12.2008)
Ответ

Метки
классы, объектов, продолжение, поддерживающие, транзакции.


Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.

Быстрый переход

Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
[Руководство] Классы объектов, поддерживающие транзакции shagart С/С++ 0 05.12.2008 18:17
[Руководство] Управление памятью. Продолжение shagart С/С++ 0 05.12.2008 18:16

Заявление об ответственности / Список мошенников

Часовой пояс GMT +4, время: 13:53.

Пишите нам: [email protected]
Copyright © 2024 vBulletin Solutions, Inc.
Translate: zCarot. Webdesign by DevArt (Fox)
G-gaMe! Team production | Since 2008
Hosted by GShost.net