Реализация smart-указателя

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

template <typename T>

struct Status { T *RealPtr; int Count;

};

template <typename T>

class Point

{ Status <T> *StatPtr;

Public:

Point (T * ptr = 0);

Point(const Point & );

~Point();

Point & operator =(const Point &);

T * operator->() const;

T & operator*() const;

void get_count() {cout<<StatPtr->Count<<endl;}

};

template<typename T>

Point<T>::Point(T * ptr)

{ if(!ptr)

StatPtr = NULL;

else

{ StatPtr = new Status <T>; StatPtr->RealPtr=ptr; StatPtr->Count = 1;

}

}

template <typename T>

Point<T>::Point(const Point & p): StatPtr(p.StatPtr)

{ if(StatPtr) StatPtr->Count++;

}

template <typename T>

Point<T>::~Point()

{ if(StatPtr)

{ StatPtr->Count--;

if(StatPtr->Count <= 0)

{delete StatPtr->RealPtr; delete StatPtr;

}

}

}

template <typename T>

T * Point <T>::operator->() const

{ if(StatPtr)

return StatPtr->RealPtr;

else return NULL;

}

template <typename T>

T & Point<T>::operator *() const

{ if(StatPtr) return *StatPtr->RealPtr;

else throw "Opps";

}

template <typename T>

Point<T> & Point<T>::operator =(const Point & p)

{ if(StatPtr)

{StatPtr->Count--;

if(StatPtr->Count <= 0)

{delete StatPtr->RealPtr; delete StatPtr;

}

}

StatPtr = p.StatPtr;

if(StatPtr) StatPtr->Count++; return * this;

}

struct Str

{ int a;

char c;

};

int main()

{ Point<Str> pt1(new Str); // генерация класса Point, конструирование

// объекта pt1, инициализируемого указателем

// на структуру Str, далее с объектом можно

// обращаться как с указателем

Point<Str> pt2=pt1,pt3; // для pt2 вызывается конструктор копирования,

// затем создается указатель pt3

pt3=pt1; // pt3 переназначается на объект указателя pt1

(*pt1).a=12; // operator*() получает this указатель на pt1

(*pt1).c='b';

int X=pt1->a; // operator->() получает this-указатель на pt1

char C=pt1->c;

return 0:

}

47.Свойства в С++.

В общем случае, свойство − это пара функций (public), одна из которых отвечает за установку компонент-данных (private) объекта, а другая за их считывание. Такое решение позволяет обеспечить инкапсуляцию данных. Необходимость использования свойств возникает тогда, когда при изменении некоторого параметра требуется произвести ещё некоторые действия.

Наиболее простой способ обеспечения инкапсуляции в C++ заключается в написании пары функций типа get_val() и put_val() для каждого параметра.

Модификатор _declspec получил дополнительный параметр «property». Это позволяет

в классе объявить «виртуальную» переменную и связать её с соответствующими

функциями.

class cls

{ int m;

public:

_declspec(property(get=get_val, put=put_val)) int V;

int get_val()

{ return m; }

void put_val(int v)

{ m = v; }

};

Мэин:

cls obj;

obj.V = 50; // при этом выполняется вызов put_val()

int k = obj.V; // при этом выполняется вызов get_val()

Основной недостаток:

Зависимость от компилятора. Нарушается инкапсуляция

Транзакции.

Транзакция может быть выполнена либо целиком и успешно, соблюдая целостность данных и независимо от параллельно идущих других транзакций, либо не выполнена вообще и тогда она не должна произвести никакого эффекта.

Пример: Необходимо перевести с банковского счёта номер 5 на счёт номер 7 сумму в 10 денежных единиц. Этого можно достичь, к примеру, приведённой последовательностью действий:

  • Начать транзакцию( прочесть баланс на счету номер 5; уменьшить баланс на 10 денежных единиц;сохранить новый баланс счёта номер 5;прочесть баланс на счету номер 7;увеличить баланс на 10 денежных единиц; сохранить новый баланс счёта номер 7
  • Окончить транзакцию

Эти действия представляют из себя логическую единицу работы «перевод суммы между счетами», и таким образом, являются транзакцией. Если прервать данную транзакцию, к примеру, в середине, и не аннулировать все изменения, легко оставить владельца счёта номер 5 без 10 единиц, тогда как владелец счета номер 7 их не получит.

____________________

template <class T1>

class A

{

T1 x;

public:

void set(T1 X){x=X;}

T1 get(){return x;}

void Show(){cout<<x<<endl;}

};

template <class T2>

class Tran

{

T2 *that; //текущее значение объекта класса A

T2 *prev; //предыдущее…

public:

Tran(){prev = NULL; that = new T2;}

Tran(const Tran &obj):that(new T2(*(obj.that))),prev(NULL){}//constr copy for A

~Tran() {delete prev; delete that;}

Tran &operator = (const Tran & obj);

void Show();

void Begin_Tran(); //начать

void Commit(); //закрепить

void Del_Tran(); //отменить

T2 *operator->();

};

template <class T2>

Tran <T2> & Tran <T2>::operator = (const Tran & obj)

{

if(this!=&obj) { delete that; that = new T2(*(obj.that)); } //prev не трогаем, чтобы

return *this; // можно было сделать откат

}

Наши рекомендации