#pragma once
template<class T_C> class T_SmartRefPtr
{
T_C* m_Ptr;
int* m_Ref;
public:
friend class T_SmartRefPtr;
T_C* operator->(){return m_Ptr;}
T_C& operator *(){return *m_Ptr;}
T_SmartRefPtr()
:m_Ptr(new T_C)
,m_Ref(new int(1))
{}
T_SmartRefPtr(T_C* ptr)
:m_Ptr(ptr)
,m_Ref(new int(1))
{}
T_SmartRefPtr(const T_SmartRefPtr& h)
:m_Ptr(h.m_Ptr)
,m_Ref(h.m_Ref)
{
(*m_Ref)++;
}
template<class T_CP1>T_SmartRefPtr(const T_SmartRefPtr<T_CP1>& h)
:m_Ptr(h.m_Ptr)
,m_Ref(h.m_Ref)
{
(*m_Ref)++;
}
T_SmartRefPtr& operator=(const T_SmartRefPtr& h)
{
if(m_Ptr==h.m_Ptr) return *this;
if(--(*m_Ref)==0)
{
delete m_Ptr;
delete m_Ref;
}
m_Ptr=h.m_Ptr;
m_Ref=h.m_Ref;
(*m_Ref)++;
return *this;
}
template<class T_CP1>T_SmartRefPtr& operator=(const T_SmartRefPtr<T_CP1>& h)
{
if(m_Ptr==h.m_Ptr) return *this;
if(--(*m_Ref)==0)
{
delete m_Ptr;
delete m_Ref;
}
m_Ptr=h.m_Ptr;
m_Ref=h.m_Ref;
(*m_Ref)++;
return *this;
}
~T_SmartRefPtr()
{
if(--(*m_Ref)==0)
{
delete m_Ptr;
delete m_Ref;
}
}
};
Здравствуйте WolfHound,
Вы писали:
WH>WH>#pragma once
WH>template<class T_C> class T_SmartRefPtr
WH>{
WH> T_C* m_Ptr;
WH> int* m_Ref;
WH>public:
[...]
WH> T_SmartRefPtr& operator=(const T_SmartRefPtr& h)
WH> {
WH> if(m_Ptr==h.m_Ptr) return *this;
WH> if(--(*m_Ref)==0)
WH> {
WH> delete m_Ptr;
WH> delete m_Ref;
WH> }
WH> m_Ptr=h.m_Ptr;
WH> m_Ref=h.m_Ref;
WH> (*m_Ref)++;
WH> return *this;
WH> }
WH> template<class T_CP1>T_SmartRefPtr& operator=(const T_SmartRefPtr<T_CP1>& h)
WH> {
WH> if(m_Ptr==h.m_Ptr) return *this;
WH> if(--(*m_Ref)==0)
WH> {
WH> delete m_Ptr;
WH> delete m_Ref;
WH> }
WH> m_Ptr=h.m_Ptr;
WH> m_Ref=h.m_Ref;
WH> (*m_Ref)++;
WH> return *this;
WH> }
[...]
WH>
Попытка создать умный указатель не внося изменений в управляемый класс?
Здорово
!
Правда, есть два недочета
.
1) Создание второго счетчика ссылок, после преобразования указатель
в класс T_C* и обратно. Данный недостаток может быть исправлен,
только отказом от использования в программе обычного указателя T_C* .
(Оператор преобразования к классу T_C* не описан специально
?)
2) досрочное разрушение обьектов в операторе "=" (обьект удаляется
до того как счетчи ссылок присваемого обьекта будет увеличн. Например:
class Data
{
public:
int i;
};
class RefAndData: public Data;
{
public:
T_SmartRefPtr<Data> pChild;
};
void main(void)
{
T_SmartRefPtr<RefAndData> pItem;
pItem->pChild=new RefOnData;
pItem=pItem->Child; // Fail
};
А вот это можно исправить:
T_SmartRefPtr& operator=(const T_SmartRefPtr& h)
{
if(m_Ptr==h.m_Ptr) return *this;
T_SmartRefPtr controll(*this);
--(*m_Ref);
m_Ptr=h.m_Ptr;
m_Ref=h.m_Ref;
(*m_Ref)++;
return *this;
}
Еще несколько коментариев:
3) Конструктор копирования (и оператор присваивания) для класса T_SmartRefPtr<T_C>
не нужен (он перекрывается конструктором для T_SmartRefPtr<T_CP1>. Более того, при
компиляции на MSVC6SP5, с обоими вариантами конструкторов копирования выдается ошибка :
d:\user\tst_3\tst refptr.cpp(29) : error C2535: '__thiscall T_SmartRefPtr<T_CP1>::T_SmartRefPtr<T_CP1>(const class T_SmartRefPtr<T_CP1> &)' : member function already defined or declared
d:\user\tst_3\tst refptr.cpp(21) : see declaration of 'T_SmartRefPtr<T_C>::T_SmartRefPtr<T_C>'
d:\user\tst_3\tst refptr.cpp(72) : see reference to class template instantiation 'T_SmartRefPtr<T_C>' being compiled
4) В шаблоне преобразования типа из необходимо явно указать преобразование
типа TCP1* в T_C*.
P.S. По поводу "new int", "delete m_Ref", может быть выделять
память в отдельной куче, для "Очень маленьких" блоков?
P.S.S. Вряд ли возможен качественный subj без внесения изменений
в управляемый класс.
Здравствуйте Chorkov, Вы писали:
C>1) Создание второго счетчика ссылок, после преобразования указатель
C>в класс T_C* и обратно. Данный недостаток может быть исправлен,
C>только отказом от использования в программе обычного указателя T_C* .
Есть такие грабли но идей пока нет.
C> (Оператор преобразования к классу T_C* не описан специально ?)
Исправлю.
C>2) досрочное разрушение обьектов в операторе "=" (обьект удаляется
C>до того как счетчи ссылок присваемого обьекта будет увеличн. Например:
Не учел исправлю.
C>Еще несколько коментариев:
C>3) Конструктор копирования (и оператор присваивания) для класса T_SmartRefPtr<T_C>
C>не нужен (он перекрывается конструктором для T_SmartRefPtr<T_CP1>.
C>Более того, при компиляции на MSVC6SP5, с обоими вариантами конструкторов копирования выдается ошибка :
MSVC7 не перекрывает, а создает по умолчанию.
Интересно а что думает стандарт?
C>4) В шаблоне преобразования типа из необходимо явно указать преобразование
C>типа TCP1* в T_C*.
Принципиально
:
class A
{
};
class B
:public A
{
};
int main()
{
T_SmartRefPtr<A> a;
T_SmartRefPtr<B> b;
a=b;//можно
b=a;//нельзя!!!!
return 0;
}
Я уже не говорю про:
T_SmartRefPtr<int> i;
T_SmartRefPtr<float> f;
i=f;//нельзя!!!!
f=i;//нельзя!!!!
C>P.S. По поводу "new int", "delete m_Ref", может быть выделять
C>память в отдельной куче, для "Очень маленьких" блоков?
Подумаю.
C>P.S.S. Вряд ли возможен качественный subj без внесения изменений
C>в управляемый класс.
Посмотрим.
ЗЫ спасибо за критику.
#pragma once
template<class T_C> class T_SmartRefPtr
{
T_C* m_Ptr;
int* m_Ref;
T_SmartRefPtr(T_C* ptr)
:m_Ptr(ptr)
,m_Ref(new int(1))
{}
public:
friend class T_SmartRefPtr;
T_C* operator->(){return m_Ptr;}
T_C& operator *(){return *m_Ptr;}
operator T_C*(){return m_Ptr;}
T_SmartRefPtr()
:m_Ptr(new T_C)
,m_Ref(new int(1))
{}
T_SmartRefPtr(const T_SmartRefPtr& h)
:m_Ptr(h.m_Ptr)
,m_Ref(h.m_Ref)
{
++(*m_Ref);
}
template<class T_CP1>T_SmartRefPtr(const T_SmartRefPtr<T_CP1>& h)
:m_Ptr(h.m_Ptr)
,m_Ref(h.m_Ref)
{
++(*m_Ref);
}
T_SmartRefPtr& operator=(const T_SmartRefPtr& h)
{
if(m_Ptr==h.m_Ptr) return *this;
T_C* t_Ptr=m_Ptr;
int* t_Ref=m_Ref;
m_Ptr=h.m_Ptr;
m_Ref=h.m_Ref;
++(*m_Ref);
if(--(*t_Ref)==0)
{
delete t_Ptr;
delete t_Ref;
}
return *this;
}
template<class T_CP1>T_SmartRefPtr& operator=(const T_SmartRefPtr<T_CP1>& h)
{
if(m_Ptr==h.m_Ptr) return *this;
T_C* t_Ptr=m_Ptr;
int* t_Ref=m_Ref;
m_Ptr=h.m_Ptr;
m_Ref=h.m_Ref;
++(*m_Ref);
if(--(*t_Ref)==0)
{
delete t_Ptr;
delete t_Ref;
}
return *this;
}
~T_SmartRefPtr()
{
if(--(*m_Ref)==0)
{
delete m_Ptr;
delete m_Ref;
}
}
//Размерности можно добавлять по вкусу.
static T_SmartRefPtr<T_C> Create()
{return T_SmartRefPtr<T_C>(new T_C());}
template<class T_CP1>
static T_SmartRefPtr<T_C> Create(T_CP1 arg1)
{return T_SmartRefPtr<T_C>(new T_C(arg1));}
template<class T_CP1, class T_CP2>
static T_SmartRefPtr<T_C> Create(T_CP1 arg1, T_CP2 arg2)
{return T_SmartRefPtr<T_C>(new T_C(arg1, arg2));}
template<class T_CP1, class T_CP2, class T_CP3>
static T_SmartRefPtr<T_C> Create(T_CP1 arg1, T_CP2 arg2, T_CP3 arg3)
{return T_SmartRefPtr<T_C>(new T_C(arg1, arg2, arg3));}
template<class T_CP1, class T_CP2, class T_CP3, class T_CP4>
static T_SmartRefPtr<T_C> Create(T_CP1 arg1, T_CP2 arg2, T_CP3 arg3, T_CP4 arg4)
{return T_SmartRefPtr<T_C>(new T_C(arg1, arg2, arg3, arg4));}
template<class T_CP1, class T_CP2, class T_CP3, class T_CP4, class T_CP5>
static T_SmartRefPtr<T_C> Create(T_CP1 arg1, T_CP2 arg2, T_CP3 arg3, T_CP4 arg4, T_CP5 arg5)
{return T_SmartRefPtr<T_C>(new T_C(arg1, arg2, arg3, arg4, arg5));}
};
Тестовый пример:
class Shape
{
protected:
char* m_s;
public:
Shape() {m_s="()"; printf(" Shape() %s\n", m_s);}
Shape(int w) {m_s="int w"; printf(" Shape() %s\n", m_s);}
Shape(int w, char* s) {m_s=s; printf(" Shape() int=%i : char*=%s\n", w, s);}
Shape(char* s, int w) {m_s=s; printf(" Shape() char*=%s : int=%i\n", s, w);}
virtual ~Shape(){printf("~Shape() %s\n", m_s);}
};
class Circle
:public Shape
{
public:
Circle() {m_s="()"; printf(" Circle() %s\n", m_s);}
Circle(int w) {m_s="int w"; printf(" Circle() %s\n", m_s);}
Circle(int w, char* s) {m_s=s; printf(" Circle() int=%i : char*=%s\n", w, s);}
Circle(char* s, int w) {m_s=s; printf(" Circle() char*=%s : int=%i\n", s, w);}
virtual ~Circle(){printf("~Circle() %s\n", m_s);}
};
int _tmain(int argc, _TCHAR* argv[])
{
T_SmartRefPtr<Shape> s0;
T_SmartRefPtr<Shape> s1=T_SmartRefPtr<Shape>::Create(10, "hi1");
T_SmartRefPtr<Shape> s2=T_SmartRefPtr<Shape>::Create("hi2", 10);
T_SmartRefPtr<Shape> s3=T_SmartRefPtr<Shape>::Create(10);
T_SmartRefPtr<Circle> s4=T_SmartRefPtr<Circle>::Create("hi2c", 10);
s1=s4;
s0=s4;
//delete s0;//Единственные известные грабли
}
ЗЫ выглядит страшно но что не сделаеш ради избавления от граблей
ЗЗЫ блин tab'ы глючат