Незамысловатый шаблон, который по функциям похож на умную ссылку из STL, только ведёт он себя немного умнее.
template<class T> class auto_ref{ struct item_st{ int count; T obj; }*data_ref; void Free(item_st *ref) { if(!ref) return; if(!--ref->count) delete ref; } void New() { if(data_ref) return; data_ref=new item_st; data_ref->count=1; } public: operator =(auto_ref &obj) { item_st *temp=data_ref; data_ref=obj.data_ref; if(data_ref) data_ref->count++; Free(temp); } operator =(const T &value) { New(); data_ref->obj=value; } T *operator ->() { New(); return &data_ref->obj; } operator T() { New(); return data_ref->obj; } auto_ref() { data_ref=0; } auto_ref(auto_ref &obj) { operator=(obj); } ~auto_ref() { Free(data_ref); } }; |
Сама идея данной конструкции давно витает внутри библиотек Qt. В основном применяется для строк. Мой вариант возможно слишком перегружен проверками. Не хочется подробно расписывать его работу, надеюсь всё понятно из исходника. Применять его очень просто:
void Hello() { auto_ptr<double> obj1,obj2; obj1=1.7; obj2=obj1; double f=obj2; } |
В данном случае объекты obj1,obj2 по смыслу и внешним свойствам ничем не будут отличаться от обычной double переменной. Разница в том что на самом деле они содержат в себе ссылку на одно и тоже double число. И само это число будет благополучно удалено во время выхода из функции. Вместо double вы можете подсунуть любой тип, структуру или класс. Так же вы можете приравнивать ссылки друг другу и делать с ними всё что захотите. Ссылка на ваш объект будет попросту дублироваться. Присваивание ссылки самой себе, перекрёстные ссылки, и любые другие фокусы, не смогут нарушить работу по подсчёту и удалению. Корректная работа и удаление уже ненужных объектов, гарантируется абсолютно в любом случае!
Продвинутые примеры:
struct data_st{int a;int b;}; void main() { auto_ref<double>ref1,ref2; auto_ref<data_st>ref3,ref4; ref1=ref2; ref1=3.1415926; ref3->a=1; ref2=ref1; ref1=ref2; ref1=ref1; ref4=ref3; ref3=ref4; double f=ref2; ref4->b=ref4->a; } |
struct data_st{int a;int b;}; void main() { auto_ref<item_st>ref1; _auto_ref<item_st>ref2; // ref1=ref2; - недопустимо (ref2 не может быть источником) ref2=ref1; ref1=ref2; ref1=ref1; ref2=ref2; |
Само присваивание данных от ссылки которая не является источником, не вызовет проблем. Но вот обращение к данным, которые должна представлять ссылка, вызовет падение программы. Добавлены две небольшие функции:
class auto_ref { .... template<T> class Proxy { T *ref; public: Proxy(T* obj):ref(obj) { \\ lock } ~Proxy() { \\ unlock } T* operator->() { return ref; } }; Proxy<item_st*>operator ->() { return Proxy<item_st*>(data_ref); } ... }; |
Во время вызова функции через оператор -> в стеке создаётся временный объект, через который вызывается наш класс. Соотвественно конструктор и деструктор временного объекта, отвечают на блокировку совместного доступа. На примере это работает так:
class Test{ public: void test() { \\ test } }; main() { auto_ref<Test>obj; obj->test(); ... } |
Разумеется блокировка всего лишь пример создания прокладок для вызова. Для этого фокуса можно придумать и другое полезное применение.
T* operator -> (); T* operator -> () const; |