Идиомы и стили С++ - страница 20

Шрифт
Интервал

стр.

А что касается виртуальных функций, то и MFC, и OWL, и VCL - все используют их как можно реже - на то веские причины! Если бы все функции в них были виртуальными, то с полметра памяти уходило бы в каждой программе только на поддержание виртуальных таблиц, да по лишнему указателю в каждом объекте.

Есть такое правило "80-20": 20 процентов кода вызывает 80 процентов затруднений, 20 процентов кода занимает 80 процентов процессорного времени. Возможно, оно даже сильнее - "90-10". В данном Шаге это значит - не зашивайтесь в "дешевой" части кода.

В общем, я хочу сказать - перед тем, как применять какую-то технику, оцените - какие усилия Вы затратите на ее освоение, ее поддержание, и какой результат Вы получите (ожидаете получить), и пригодятся ли Вам эти знания в будущем, что тоже важно. Программирование - всегда поиск компромисса между затратами времени, пространства и (!)труда, не забывайте что Ваш день стоит минимум как небольшой DIMM. Надеюсь.

Шаг 22 - Классы объектов, поддерживающие транзакции.

Бывает особенно приятно, когда занимаешься теорией. Занимаешься, думаешь: "ну никакой связи с жизнью, хоть бы минимум пользы"… и вдруг раз! и польза является во всей своей красе, блистая в лучах солнца и хрустя пачками денег. Что чувствовал Менделеев, когда после долгих изысканий, жутких таблиц, являвшихся ему в ночных кошмарах, вдруг получил-таки нормальную, не паленую, 40-градусную водку? Или Эйлер, когда, после терзаний и депрессий, извлек таки сопротивляющийся, визжащий и цепляющийся щупальцами и жвалами квадратный корень из минус единицы? К чему это я? А вот к чему: концепция smart-указателей может предложить простые и прозрачные решения для некоторых сложных задач; и если Вы считаете, что поддержка транзакций (а так же многоуровневой отмены и повтора) есть сложная задача, то смарты помогут Вам с замечательной легкостью.

Вспомним для начала, что делает транзакция:

1. Если транзакция началась, то все изменения в ней либо вносятся вместе, либо не вносятся вообще (это вообще определение транзакции).

2. Если клиент начал и не завершил транзакцию, то другие клиенты не видят его изменений.

3. Две транзакции не могут одновременно изменять одни и те же данные.

Начнем с первого пункта. Если мы хотим закрепить или отменить проведенные изменения, нужно хранить состояние объекта на заданный момент - начало транзакции, и в момент принятия решения или уничтожать предыдущее состояние (закрепление) или возвращаться к нему (отмена). Пусть обслуживанием занимается smart-указатель. Кладем в него два указателя - один на текущий объект, а второй - на объект, представляющий его предыдущее состояние, и три функции - старт, закрепление, отмена.

>#include ‹iostream.h›

>// Некий скромный класс.

>class CSomeClass {

>public:

> int x;

> int y;

>};


>// Его оплетка: smart-pointer с поддержкой отмены.

>class CSimpleTr {

>public:

> CSomeClass* that; // текущее значение

> CSomeClass* previos; // предыдущее значение

>public:

> // конструктор-деструктор-присваивание-копирование

> CSimpleTr(): previos(NULL), that(new CSomeClass) {}

> CSimpleTr(const CSimpleTr& _st): that(new CSomeClass(*(_st.that))), previos(NULL) {}

> ~CSimpleTr() {delete that; delete previos;}

> CSimpleTr& operator=(const CSimpleTr& _st) {

>  if (this!=&_st) {

>   delete that;

>   that = new CSomeClass(*(_st.that));

>  }

>  return *this;

> }

> // начало транзакции

> void BeginTrans() {

>  delete previos;

>  previos = that;

>  that = new CSomeClass(*previos);

> }

> // закрепление

> void Commit() {

>  delete previos;

>  previos = NULL;

> }

> // отмена транзакции

> void Rollback() {

>  if (previos != NULL) {

>   delete that;

>   that = previos;

>   previos = NULL;

>  }

> }

> // реализация указателя

> CSomeClass* operator-›() { return that; }

>};


>int main (void) {

> // проверим быстренько

> CSimpleTr lvPair;

> lvPair-›x = 5;

> lvPair-›y = 8;

> lvPair.BeginTrans();

> lvPair-›x = 7;

> lvPair-›y = 11;

> lvPair.Rollback();

> lvPair.BeginTrans();

> lvPair-›x = 7;

> lvPair-›y = 11;

> lvPair.Commit();

> return 0;

>}

Что может быть проще? Семантика значений, очевидно. Классы должны иметь полный набор обязательных функций, как обычно; в нашем случае класс


стр.

Похожие книги