首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 软件管理 > 软件架构设计 >

句柄种

2013-09-24 
句柄类1 class Point 2 {/*{{{*/ 3 public: 4Point():_x(0),_y(0){} 5Point(int x,int y):_x(x),_y(y){} 6

句柄类

 

 

 1 class Point 2 {/*{{{*/ 3 public: 4     Point():_x(0),_y(0){} 5     Point(int x,int y):_x(x),_y(y){} 6     int x()const {return _x;} 7     void x(int xv) { _x = xv;} 8     int y()const { return _y;} 9     void y(int yv) { _y = yv;}10 private:11     int _x;12     int _y;13 };/*}}}*/

接下来我们要定义其的Handle类.

我们的Handle类:

 1 class Handle 2 { 3 public: 4     Handle():up(new UPoint){} 5     Handle(int x,int y):up(new UPoint(x,y)){} 6     Handle(const Point&p):up(new UPoint(p)){} 7     Handle(const Handle &h); 8     ~Handle(); 9     Handle& operator=(const Handle &h);10     int x() const{ return up->p.x(); }11     int y() const{ return up->p.y(); }12     Handle& x(int);13     Handle& y(int);14 15     16 private:17     UPoint *up;18     void allocup();19 };

这里说明我们的Handle和指针的不同之处.

也许有读者会对Handle有疑问,为什么不采用operator->来直接操作point呢?

其实顾虑就是operator->返回的是point的地址.也就是使用者可以轻易的获得point的地址进行操作,这并不是我们想要的.这也就是Handle也pointer不想同的地方.

UPoint是为了采用引用计数定义的数据结构

 1 //all member is private..only assess by Handle 2 class UPoint 3 {/*{{{*/ 4   friend class Handle; 5    6   Point p; 7   int u;//count 8  9   UPoint():u(0){}10   UPoint(const Point&pv):p(pv){}11   UPoint(int x,int y):p(x,y),u(1){}12   UPoint(const UPoint &up):p(up.p),u(1){}13 };/*}}}*/

 

对于Handle类的操作,我们要在Handle类进行复制的时候,累加Handle指向的UPoint的计数值

即复制构造函数以及赋值函数

 1 Handle::Handle(const Handle &h) 2     :up(h.up) 3 { 4   ++up->u; 5 } 6  7 Handle& Handle::operator=(const Handle &h) 8 { 9    ++h.up->u;10   if (--up->u == 0)11       delete up;12   up = h.up;13   return *this;14 }

而对于析构函数,则是减小引用计数,如果减到0了,就说明没有其他的Handle指向了UPoint,因此我们要删除掉.

 1 //point like 2 Handle& Handle::x(int xv) 3 { 4   up->p.x(xv); 5   return *this; 6 } 7 //point like 8 Handle& Handle::y(int yv) 9 {10   up->p.y(yv);11   return *this;12 }

 

还有一种是写时复制技术,即每次对于共享的Point进行修改的时候都复制一份新的Point,然后进行修改.

这种技术在Handle中大量采用.在stl中,string也采用了同样的方法.

其额外开销很小,而效率也不差.

代码:

 1 void Handle::allocup() 2 { 3    if (up->u != 1) 4    { 5     --up->u; 6     up = new UPoint(up->p); 7    } 8 } 9 10 Handle& Handle::x(int xv)11 {12    allocup();13    up->p.x(xv);14    return *this;15 }16 17 Handle& Handle::y(int yv)18 {19    allocup();20    up->p.y(yv);21    return *this;22 }
 1 class Point 2 {/*{{{*/ 3 public: 4     Point():_x(0),_y(0){} 5     Point(int x,int y):_x(x),_y(y){} 6     int x()const {return _x;} 7     void x(int xv) { _x = xv;} 8     int y()const { return _y;} 9     void y(int yv) { _y = yv;}10 private:11     int _x;12     int _y;13 };/*}}}*/14 15 16 //all member is private..only assess by Handle17 class UPoint18 {/*{{{*/19   friend class Handle;20   21   Point p;22   int u;//count23 24 //省略25 };/*}}}*/26 27 class Handle28 {29 public:30     //省略31 32 private:33     UPoint *up;34 };

可以看到,计数是由UPoint来实现的.由Handle来管理.

但做为编写者的我们肯定是不愿意这么写的.这意味着每写一个Handle都得写一个这样的Uxxxx.实在是费事.

因此,我们可以很直观的想到一个写法,即在Handle里面指向的是Point *p和int *count;

这样就没有这个麻烦了.

当然这是一个很好的解决方案.

这里我再提出一种方案,即抽象引用计数,增加一个UseCount类.

通过这个类来计数.其是通用的.所有的Handle都可以使用.其次,这可以减少我们的指针操作.

实例如下:

被Handle管理的类的声明:

 1 class Point 2 {/*{{{*/ 3 public: 4     Point():_x(0),_y(0){} 5     Point(int x,int y):_x(x),_y(y){} 6     int x()const {return _x;} 7     void x(int xv) { _x = xv;} 8     int y()const { return _y;} 9     void y(int yv) { _y = yv;}10 private:11     int _x;12     int _y;13 };/*}}}*/

这个和原来的是一样的.

再来看看我们的UseCount

 1 class UseCount 2 { 3 public: 4     UseCount():count(new int(1)){} 5     UseCount(const UseCount& uc):count(uc.count){ ++*count;} 6     UseCount& operator=(const UseCount &u); 7     ~UseCount(); 8     bool isonly() { return *count == 1;}//判断是否只指向一个计数,用于判断是否要删除 9     bool reattach(const UseCount &u);//重新连接,用于复制10     bool makeonly();//分配一个新的,用于写时复制技术11 private:12     int *count;//计数13 };14 15 UseCount& UseCount::operator=(const UseCount &u)16 {17    reattach(u);18    return *this;19 }20 21 UseCount::~UseCount()22 {23    if (--*count == 0)24     delete count;25 }26 bool UseCount::reattach(const UseCount &u)27 {28   29   ++*u.count;30   if (-- *u.count == 0)31   {32      delete count;33      count = u.count;34      return true;     35   }36   count = u.count;37   return false; 38 }39 40 bool UseCount::makeonly()41 {42   if (*count == 1)43     return false;44   --*count;45   count = new int(1);46   return true;47 }

这个类实现了计数的功能.其内部有一个count的int 指针.在进行UseCount的复制的时候仅仅是++use.

其他的功能函数我也加了注释.大家应该能看懂.

剩下的就是我们的使用UseCount的Handle类了.

 1 class Handle 2 { 3 public: 4     Handle():p(new Point){} 5     Handle(int x,int y):p(new Point(x,y)){}//使用了UseCount使得我们的构造函数显得异常简单, 6     Handle(const Point&pp):p(new Point(pp)){}//仅仅是分配了Point的空间而已 7     Handle(const Handle &h):p(h.p),count(h.count){};//复制构造函数也很简单.其实可以省略,也不会出错 8     ~Handle(); 9     Handle& operator=(const Handle &h);10     int x() const{ return p->x(); }11     int y() const{ return p->y(); }12     Handle& x(int);13     Handle& y(int);14 15     16 private:17     Point *p;//被Handle的对象18     UseCount count;//使用UseCount19 };

我们来看看各个函数

析构函数:

1 Handle& Handle::operator=(const Handle &h)2 {3   if (count.reattach(h.count))4       delete p;5   p = h.p;6   return *this;7 }

reattach函数返回bool指,如果count == 1的话,返回值为true,那就要把p给删除.

采用了写时复制技术的x(int),y(int)

 1 Handle& Handle::x(int x0) 2 { 3   if (count.makeonly()) 4       p = new Point(*p); 5   p->x(x0); 6   return *this; 7 } 8  9 Handle& Handle::y(int y0)10 {11    if (count.makeonly())12      p = new Point(*p);13    p->y(y0);14    return *this;15 16 }

makeonly()使UseCount分配一个新的计数值,返回true说明需要分配,false则代表其本身就只指向了一个对象,不需要重新分配.

最后是咱们的测试main函数

 1 int main() 2 { 3   Handle h(10,10); 4   cout << h.x() << " " << h.y() << endl; 5   h.x(20); 6   cout << h.x() << " " << h.y() << endl;  7   Handle h2(h); 8   cout << h2.x() << " " << h2.y() << endl; 9   return 0;  10 }

总结:

      我们可以看到,通过抽象计数对象,我们的Handle的操作显得特别简单,减少了很多的指针操作.同时也减少了出错的可能.

      而通过这个方法,我们也减少了一个UPoint类的书写.简化了操作.

  Handle类有智能指针一说.其行为有点像指针.同时又省却了我们指针操作的麻烦.而且,减少了很多复制的操作.效率和代码的健壮性得到了提高.

     

热点排行