C++ Handle(句柄) part1
本文是我学习C++沉思录第6章的笔记
本文主要讲述了Handle类的概念,定义方法以及写时复制技术。
在前文(Surrogate代理类)的讲解中我们了解到了代理的实现方法.
代理类有很多好处,但是麻烦的是每次都得进行复制.如果该类是经常使用并且member很多的话,这样复制的消耗是十分客观的.
因此这里就要介绍另外一种代理类,Handle,也就是句柄类.
为何使用句柄类?
首先就是复制问题.前面有谈到,有些类内部数据很多,采用复制消耗非常大,这种情况下就必须采用句柄类来进行操作.
其次是由于函数的参数和返回值都是采用了复制进行自动传递.虽然c++中引用可以避免,但是很多情况下返回值采用引用并不明智.
对于采用指针的方式,可以解决问题,但是又会引入调用者对于动态管理内存的麻烦.而这往往是很多错误的根源.
何为句柄类呢?
句柄类可以理解为采用了引用计数的代理类.
其多个句柄共享了同一个被代理的类.通过引用计数的方式来减少复制以及内存管理.
其行为类似指针,因此也有智能指针之称,但其实差别很大.后面会有讲述.
句柄类例子:
先有一个简单的类Point
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 Handle::~Handle()2 {3 if (--up->u == 0)4 delete up;5 }
剩下的就是定义Handle对于Point的操作了.即Handle::x(int xv)和Handle::(int yv)了.
这里有2种写法.
一种是像指针一样,对于赋值,就直接修改指向的Point里面的值.这种方法有一个问题,即所以都指向这个Point的Handle类获取的x值都会变化.
代码:
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 }
至此,Handle类的第一部分就讲完了.
之后会有第二部分的讲解.解决了多出了一个UPoint的麻烦.
C++ Handle(句柄) part1相关推荐
- HANDLE:句柄的概念
HANDLE:句柄,是Windows用来表示对象的(不是C++的对象),HWND是其中一种,HWND是HANDLE,但HANDLE不只是HWND,HANDLE是一个通用句柄表示,HWND是一个专用表示 ...
- handle句柄 matlab_学习随笔之Matlab句柄对象深拷贝方法
最近在使用Matlab句柄对象时,被深拷贝和浅拷贝的坑折腾得不轻,而且网上相关的应用资料也比较少,好在MathWork的帮助文档非常丰富,并且有应用案例,花了几天时间终于理出了一些头绪,以下是自己使用 ...
- c语言windows编程句柄,HANDLE句柄(windows编程)
首先什么是句柄?(理解了句柄,也就知道了句柄和指针的区别了) 所谓句柄实际上是一个数据,是一个Long (整长型)的数据. 句柄是WONDOWS用来标识被应用程序所建立或使用的对象的唯一整数,WIND ...
- windows下的Handle句柄和Linux下的Fd文件标示符
在操作系统层面上,文件操作也有类似于FILE的一个概念,在Linux里,这叫做文件描述符(File Descriptor),而在Windows里,叫做句柄(Handle)(以下在没有歧义的时候统称为句 ...
- 重庆大学光电工程学院 贾旭滨 对 “句柄” “指针” 有下面的描述(AfxGetMainWnd GetSafeHwnd() AfxGetAppName() AfxGetThread)...
http://www1.ustc.edu.cn/personal/csli/vc_note/frame.htm 句 柄 出处: 方塘2003.9.22 整理,之所以前面引用了 贾旭滨 先生 ...
- c语言中handle的用法,handle什么意思_handle的用法和短语例句
handle有处理;对待;操作;触;买卖;把手;柄等意思,那么你知道handle的用法吗?下面跟着学习啦小编一起来学习handle的英语知识吧,希望对大家的学习有所帮助! handle的用法 hand ...
- Windows句柄剖析
1 什么是句柄 句柄的概念: 在系统中指向某个控件或对象的唯一指针(也可叫句柄),系统可以通过这个句柄与所对应的控件或对象交互(控制它).控件或对象与句柄的关系就好比电视机与遥控器,通过遥控器 ...
- DuplicateHandle 伪句柄 与 实句柄的应用
如果把GetCurrentThread()返回值传递给一个HANDLE句柄,用它进行ResumeThread,结果肯定不是我们想要的.下面的例子详细描述了伪句柄的调用结果: #include &quo ...
- 转: IO设计模式:Reactor和Proactor对比
转: https://segmentfault.com/a/1190000002715832 平时接触的开源产品如Redis.ACE,事件模型都使用的Reactor模式:而同样做事件处理的Proact ...
最新文章
- sublime 添加代码片段(snippets)
- MM定价计算方案确定详细图解
- go与JAVA差异_20190312_浅谈gojava差异(二)
- 字符流读数据的2种方式
- 分布式系统Quorum机制
- ajax request headers,ajax request VS normal request
- win10计算机磁盘图标,Win10 21H1怎么更换电脑磁盘的图标标识
- 一道内存分配的面试题
- kubernetes 实战 使用 nfs 作为动态 storageClass 存储
- 如何设置CentOS 7开机自动获取IP地址详解
- ImageLoader简单分析(三)
- Atitit.反编译apk android源码以及防止反编译apk
- 团队软件库_R FMEA软件介绍
- UE4 骨骼重定向记录
- 专利学习笔记5:CPC客户端的安装方法
- 台式电脑怎么调分辨率_台式机屏幕分辨率不能调节怎么办
- 4.4.1小问题集锦
- ADXL345 驱动代码
- 雨水弃流装置详细说明
- ModuleNotFoundError: No module named 'torch'(anaconda安装好Pytorch却无法在Jupyter notebook使用)