Идиомы и стили С++
Шрифт:
Шаг 23 - Классы объектов, поддерживающие транзакции. Продолжение.
Раз уж взялись, что мешает вставить в наш умный указатель с поддержкой отмены не один, а несколько предыдущих состояний объекта? Ничего. Только чтобы потом несколько раз не переделывать, решим несколько чисто технических моментов:
1. Какую структуру будем использовать в качестве коллекции состояний? Можно взять стек, можно кольцевой буфер, а можно и карту (словарь, хэш-таблицу); стек явно проще, зато за кольцевым буфером можно не следить вообще, пусть устаревшие состояния пропадают бесследно (конечно по
2. Определимся с семантикой. Смешивать значения и указатели не стоит, верный путь заработать себе геморрой. У меня не оказалось под рукой подходящего стека, и я написал для этого Шага два варианта - один хранит значения, другой - указатели; первый стек сначала казался проще, но использующий его класс указателя оказался ощутимо сложнее по простой причине - функции стека с указателями могут возвращать NULL, а это совсем немало.
3. Оформим все в виде шаблонов; вообще контейнеры просто просятся быть шаблонами, а smart– указатели несомненно являются контейнерами.
Код ниже, а сейчас пояснения:
Класс CType просто проверочный, чтобы вкладывать в шаблоны; так проще отлаживать шаблон: сначала сделать контейнер-не-шаблон для класса Type, а потом просто приписать сверху объявления строку template‹Type›. Шаблон класса ampstack‹Type›– шаблон стека указателей; push сохраняет указатель, pop достает верхний указатель, isEmpty проверяет на пустоту, emptyAll очищает.
Шаблон класса MLTrans– наконец тот, который нам нужен. Указатель that хранит текущее значение, Push сохраняет текущее значение, PopOne делает однократную отмену, Rollback отменяет все изменения, до первоначального, Commit удаляет историю.