SRC: Указатель с подсчетом ссылок.
От: WolfHound  
Дата: 27.09.02 19:45
Оценка: 15 (1)
#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;
        }
    }
};
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re: SRC: Указатель с подсчетом ссылок.
От: Chorkov Россия  
Дата: 30.09.02 07:29
Оценка: 4 (1)
Здравствуйте 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 без внесения изменений
в управляемый класс.
Re[2]: SRC: Указатель с подсчетом ссылок.
От: WolfHound  
Дата: 30.09.02 09:53
Оценка:
Здравствуйте 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>в управляемый класс.
Посмотрим.

ЗЫ спасибо за критику.
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re: SRC: Указатель с подсчетом ссылок.
От: WolfHound  
Дата: 01.10.02 20:35
Оценка:
#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'ы глючат
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.