Handle类与智能指针

Handle类与智能指针的用途或者说是设计它的目的是,能够让我不必去复制对象,同时能够达到运行时绑定对象的方法

今天在前面看到了智能指针的定义及用途,后面又看到了handle类,很好奇,这二者有什么区别,于是各种google,大致得出下面的结论(仅供参考)
智能指针主要目的在于使用RAII管理资源,实现资源的自动释放。
句柄类也实现了智能指针的功能,但是其主要目的是为了在数组中实现多态。

handle类行为类似指针,复制handle对象不会复制其基础对象,复制之后,两个handle指向同一个基础对象。创建一个handle对象,用户需要传递属于有handle管理类型的动态分配对象的地址,从此刻起,handle将拥有这个对象,并且一旦不在有handle对象与该对象关联,handle类负责删除该对象。这个与指针很像,可以说二者基本一致,只是在用的领域有一些不同。

智能指针或者说Handle有三种写法

  • 1、写一个类specialClass,这个类包含需要管理成员指针和引用计数,然后定义一个handle类其中只有一个成员specialClass*管理我们刚刚那个类如下所示
 //all member is private..only assess by Handle
 class UPoint
 {
   friend class Handle;
   
   Point p;
   int u;//count
 
   UPoint():u(0){}
   UPoint(const Point&pv):p(pv){}
   UPoint(int x,int y):p(x,y),u(1){}
   UPoint(const UPoint &up):p(up.p),u(1){}
 };
//handle类管理
class Handle
{
public:
    Handle():up(new UPoint){}
    Handle(int x,int y):up(new UPoint(x,y)){}
    Handle(const Point&p):up(new UPoint(p)){}
    Handle(const Handle &h);
    ~Handle();
    Handle& operator=(const Handle &h);
    int x() const{ return up->p.x(); }
    int y() const{ return up->p.y(); }
    Handle& x(int);
    Handle& y(int);
private:
    UPoint *up;
    void allocup();
};
  • 2、可以看到第一种方法,计数是由UPoint来实现的,由Handle来管理。但做为编写者的我们肯定是不愿意这么写的.这意味着每写一个Handle都得写一个这样的Uxxxx.实在是费事。因此,我们可以很直观的想到一个写法,即在Handle里面指向的是Point *p和int *count;,有一个类似的例子如下
#ifndef MYHANDLE
#define MYHANDLE
template
class Handle
{
public:
    //默认构造函数
    Handle(T *p = 0):ptr(p),use(new size_t(1)){}
    //复制构造函数
    Handle(const Handle & rhs):ptr(rhs.ptr),use(rhs.use){(*use)++;}
    //赋值函数
    Handle & operator=(const Handle & rhs)
    {
        *(rhs.use)++;
        removeRef();
        ptr = rhs.ptr;
        use = rhs.use;
        return *this;
    }
    //析构函数
    ~Handle(){removeRef();}
    //指针解引用和箭头操作符,两个版本
    T& operator*();
    T* operator->();
    const T& operator*() const;
    const T* operator->() const;
private:
    T * ptr;
    size_t * use;
    void removeRef()
    {
        if (--(*use) == 0)
        {
            delete ptr;
            delete use;
        }
    }
};
  • 3、上述这种方法是一个很好的解决方式,但还有一种方式是定义一个引用计数类,专门用于管理引用计数,让handle管理指针的行为,如下例子
#ifndef MYUC
#define MYUC
class UseCount
{
public:
    //默认构造函数
    UseCount():count(new size_t(1)){}
    //复制构造函数
    UseCount(const UseCount& uc):count(uc.count){ ++*count;}
    //赋值操作符
    UseCount& operator=(const UseCount &u){
        reattach(u);
        return *this;
    }
    //析构函数
    ~UseCount(){ 
        if (--*count == 0)
            delete count;
    }
    bool isonly() { return *count == 1;}//判断是否只指向一个计数,用于判断是否要删除
    bool reattach(const UseCount &u);//重新连接,用于复制
    bool makeonly();//分配一个新的,用于写时复制技术
private:
    size_t *count;//计数
};
//用于定义赋值操作的时候使用
bool UseCount::reattach(const UseCount &u)
{
    ++*u.count;
    if (-- *count == 0)
    {
        delete count;
        count = u.count;
        return true;     
    }
    count = u.count;
    return false; 
}
bool UseCount::makeonly()//用于写时复制
{
    if (*count == 1)
        return false;
    --*count;
    count = new size_t(1);
    return true;
}
//handle 管理类
template
class HandleC
{
public:
    //默认构造函数
    HandleC(T *q = 0):p(q){};
    //复制构造函数
    HandleC(const HandleC &h):p(h.p),count(h.count){};//复制构造函数也很简单.其实可以省略,也不会出错
    //赋值操作符
    HandleC& operator=(const HandleC &rhs);
    //析构函数,先析构这个析构函数内的内容,在析构类的成员
    ~HandleC(){if(count.isonly()) delete p;}

    //解引用和->操作符
    T * operator->();
    T & operator*();
private:
    T *p;//被Handle的对象
    UseCount count;//使用UseCount
};
template HandleC& HandleC::operator =(const HandleC &rhs)
{
    if (count.reattch(rhs.count))
        delete p;
    p = rhs.p;
    return *this;
}
template T*HandleC::operator->()
{
    if (p) return p;
    throw std::runtime_error("access through unbound Handle");
}
template T&HandleC::operator*()
{
    if (p) return *p;
    throw std::runtime_error("dereference of unbound Handle");
}
#endif   

你可能感兴趣的:(Handle类与智能指针)