Незамысловатый шаблон, который по функциям похож на умную ссылку из 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; |