c++ Handle类的理解(2)
来源:互联网 发布:ubuntu golang 安装 编辑:程序博客网 时间:2024/05/29 02:55
上一篇中, 阐明了代理类的产生和由来原因。一切都还可以,但是美中不足的是,每次都需要进行copy操作。这无疑是不好的,尤其是对于一切可能不能复制的情况,如数据库链接,打开的文件句柄,或者由于对象很大,复制会导致较大的开销。例子嘛,还是想到了书中的例子【其他例子也可以,不过这个例子毕竟简单,可能说服性也就不太好- -,理解思想就好】
//Point类 class Point(){ private: int m_x; int m_y; public: Point():m_x(0),m_y(0){} Point(int x,int y):m_x(x),m_y(y){} //这里省略了拷贝构造函数和operator=的实现。因为默认的已经够用了 int x()const{ return m_x; } int y()const{ return m_y; } Point& x(int x){ m_x = x; return *this; } Point& y(int y){ m_y = y; return *this; } };
以上定义了一个Point类,你可以把它作用一个普通坐标上的点类来看待。这里没有什么继承层次,所以如果你看完了上篇,在看本篇时,思维还是需要稍微转变下【不在上一个基础上修改,是因为觉得代码量会比较大,偏离要表达的本意】思考: 我们考虑下,如果把本例子按照上一篇的思路来实现【可以把Point"想成“是一个有 pure virtual function的类以及还有一些子类】,当我们需要多态调用函数时,我们可能需要一个容器。这里假设直接是一个数组:并假设 PP为Point子类
Point p[100]; p[0] = PP(5,10); //不要觉得疑惑,你如果看懂了上篇,这句话应该是可以理解的。
而其中的过程是,PP(5,10)构造的匿名对象会调用copy方法,从而返回一个从堆上创建的副本并保存在p[0]中。【这里也算是对上篇的一个简单回顾】。 再次啰嗦下,本篇我们使用Handle就是为了不想有copy这样的对象复制发生!!!【哦,这么说其实吧,也容易误导人- - 】 看代码: p[1] = p[0]; 对于这样的代码,其中还是有了copy操作,我们可否省去这里的copy呢,答案是可以,我们可以共享对象。但是共享对象,什么时候该删除呢?a和b两个都引用到了同一个对象c,那么任何一个删除,如果另外一个还在用,是不是就会出问题了呢?。于是乎,解决方案出来了,引用计数! 两个或者多个对象可以共享同一个对象,每次有新的对象引用到已有的对象时,我们就把计数值+1,当有对象脱离时就把这个对象的引用计数-1,当引用计数-1 == 0 的时候,我们就删除这个对象!ok,思路理顺了,那么用代码实现看看,哦,别急。再想想,要对对象进行计数统计,我们应该把计数的放在哪里?放入Point类吗?是可以,但是这无疑是需要我们修改Point类的代码的【此处不要想着直接修改Point很容易,因为Point只是我们举得例子而已,可以想象成Point是一个已经完成的比较复杂的一个对象类!】,那么放入到我们的代理类中可以吗?想想也是不可以,为什么? 因为 代理类【Handle】类既然要共享,也就是多个Handle会绑定到同一个Point上,那么如果引用计数在Handle中,我们如何去跟踪那些引用到同一个Point的Handle对象呢?做不到这一点【或者复杂度太大】,那么引用计数自然也就不能得到正确的改变【引用计数设置为static的。- - ,别逗,100个Handle可能共享不止一个Point对象,可能前50个共享Point a,后50个共享Point b - -】。那么答案呼之欲出,我们需要一个”间接层”,这样子的话,上代码:
class Handle;//Handle类前向声明 class UPoint{ private: Point m_p; //Point int count; //引用计数变量 private: friend class Handle;//设置Handle为UPoint类的友元 UPoint():count(1){} UPoint(const Point& p):m_p(p),count(1){} UPoint(int x,int y):m_p(new Point(x,y)),count(1){} };
定义了UPoint类,作为“中间层”保存引用计数。
class Handle{ private: UPoint* m_up; public: Handle():m_up(new UPoint()){} Handle(const Handle& h):m_up(h.m_up){++m_up->count;}//增加引用计数 Handle(int x,int y):m_up(new UPoint(x,y)){} Handle& operator=(const Handle& h){ h.m_up->count++; if(--m_up->count == 0){ delete m_up; } m_up = h.m_up; return *this; } ~Handle(){ if(--m_up->count == 0){ delete m_up; } public: int x()const{ return m_up->x(); } int y()const{ return m_up->y(); } //这两个有些特殊 /* Handle& x(int x){ m_up->x(x); return *this; } Handle& y(int y){ m_up->y(y); return *this; } */ };
暂时算告一段落了,但是还没有说完,最后注释起来的两个函数有点特殊【为什么呢?】,因为它进行了写入,由于我们知道多个Handle对象可以共享Point,那么:假设Handle a和Handle b两个对象共享一个Point:
Handle h(5,5); Handle y = h; y.y(10);// h.y() == ? 此时应该是5 还是10呢?
当然了按照注释的方式来写的话,是返回10 的,但是这大多数时候可能都不是我们想要的,我们希望平时它们好好共享,当有写入发生时,就成为独立的。于是乎,写时复制(copy on write)出现了。这个技术将在下篇文章中进行讲解。
p.s.以上代码都是在写博客的过程中,按照自己的思考来书写,没有在编译器中运行。如果思想上有什么理解错误或者偏差的地方,恳请提出,谢谢。
0 0
- c++ Handle类的理解(2)
- c++ Handle类的理解
- andriod handle 的理解
- 浅谈对handle的理解
- 句柄(Handle)是什么--对句柄的简单理解。
- Android Handle机制 理解Looper、Handle、Message的关系
- 理解HANDLE
- C++, ID、指针、handle (void *)的区别
- C++, ID、指针、handle (void *)的区别
- C++, ID、指针、handle (void *)的区别
- C++, ID、指针、handle (void *)的区别
- C++, ID、指针、handle (void *)的区别
- Android的Handle类
- Android中对Handle机制的理解
- Android 之Handle的使用原理理解
- MFC中句柄HANDLE的理解
- Android中对Handle机制的理解
- Android中对Handle机制的理解
- C#调用Excel VBA宏
- 实模式、保护模式以及虚拟80806方式简介
- iGriamceV8.0 IG8.0.0 iOS8 V8基本设置和使用教程图
- Java 驼峰与下划线的属性名互相转换
- C++中智能指针的设计和使用
- c++ Handle类的理解(2)
- 【算法】求两个字符串的最长子串
- 1.1.1 对canvas的支持
- first day
- Java 基本数据类型
- 自定义组件之-利用已经用的组件进行二次的组件开发
- HDU 1248 寒冰王座 【完全背包】
- iGrimace iOS应用闪退或图标消失的解决办法
- ferror函数 (2012-11-01 14:40:30) http://blog.sina.com.cn/s/blog_735160d70101a8oh.html