本文是我学习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相关推荐

  1. HANDLE:句柄的概念

    HANDLE:句柄,是Windows用来表示对象的(不是C++的对象),HWND是其中一种,HWND是HANDLE,但HANDLE不只是HWND,HANDLE是一个通用句柄表示,HWND是一个专用表示 ...

  2. handle句柄 matlab_学习随笔之Matlab句柄对象深拷贝方法

    最近在使用Matlab句柄对象时,被深拷贝和浅拷贝的坑折腾得不轻,而且网上相关的应用资料也比较少,好在MathWork的帮助文档非常丰富,并且有应用案例,花了几天时间终于理出了一些头绪,以下是自己使用 ...

  3. c语言windows编程句柄,HANDLE句柄(windows编程)

    首先什么是句柄?(理解了句柄,也就知道了句柄和指针的区别了) 所谓句柄实际上是一个数据,是一个Long (整长型)的数据. 句柄是WONDOWS用来标识被应用程序所建立或使用的对象的唯一整数,WIND ...

  4. windows下的Handle句柄和Linux下的Fd文件标示符

    在操作系统层面上,文件操作也有类似于FILE的一个概念,在Linux里,这叫做文件描述符(File Descriptor),而在Windows里,叫做句柄(Handle)(以下在没有歧义的时候统称为句 ...

  5. 重庆大学光电工程学院 贾旭滨 对 “句柄” “指针” 有下面的描述(AfxGetMainWnd GetSafeHwnd() AfxGetAppName() AfxGetThread)...

    http://www1.ustc.edu.cn/personal/csli/vc_note/frame.htm  句      柄 出处: 方塘2003.9.22 整理,之所以前面引用了 贾旭滨 先生 ...

  6. c语言中handle的用法,handle什么意思_handle的用法和短语例句

    handle有处理;对待;操作;触;买卖;把手;柄等意思,那么你知道handle的用法吗?下面跟着学习啦小编一起来学习handle的英语知识吧,希望对大家的学习有所帮助! handle的用法 hand ...

  7. Windows句柄剖析

    1 什么是句柄 句柄的概念:     在系统中指向某个控件或对象的唯一指针(也可叫句柄),系统可以通过这个句柄与所对应的控件或对象交互(控制它).控件或对象与句柄的关系就好比电视机与遥控器,通过遥控器 ...

  8. DuplicateHandle 伪句柄 与 实句柄的应用

    如果把GetCurrentThread()返回值传递给一个HANDLE句柄,用它进行ResumeThread,结果肯定不是我们想要的.下面的例子详细描述了伪句柄的调用结果: #include &quo ...

  9. 转: IO设计模式:Reactor和Proactor对比

    转: https://segmentfault.com/a/1190000002715832 平时接触的开源产品如Redis.ACE,事件模型都使用的Reactor模式:而同样做事件处理的Proact ...

最新文章

  1. sublime 添加代码片段(snippets)
  2. MM定价计算方案确定详细图解
  3. go与JAVA差异_20190312_浅谈gojava差异(二)
  4. 字符流读数据的2种方式
  5. 分布式系统Quorum机制
  6. ajax request headers,ajax request VS normal request
  7. win10计算机磁盘图标,Win10 21H1怎么更换电脑磁盘的图标标识
  8. 一道内存分配的面试题
  9. kubernetes 实战 使用 nfs 作为动态 storageClass 存储
  10. 如何设置CentOS 7开机自动获取IP地址详解
  11. ImageLoader简单分析(三)
  12. Atitit.反编译apk android源码以及防止反编译apk
  13. 团队软件库_R FMEA软件介绍
  14. UE4 骨骼重定向记录
  15. 专利学习笔记5:CPC客户端的安装方法
  16. 台式电脑怎么调分辨率_台式机屏幕分辨率不能调节怎么办
  17. 4.4.1小问题集锦
  18. ADXL345 驱动代码
  19. 雨水弃流装置详细说明
  20. ModuleNotFoundError: No module named 'torch'(anaconda安装好Pytorch却无法在Jupyter notebook使用)

热门文章

  1. 程序员如何在大公司做管理
  2. RabbitMQ 从入门到精通 (一)
  3. 「LG2664 树上游戏」
  4. Python 字符串查找子串的方法之 index() 和 find()
  5. Nexus 安装(Linux 环境)
  6. 强名称程序集(strong name assembly)——为程序集赋予强名称
  7. 设计模式11---组合模式(Composite Pattern)
  8. 二叉树三种遍历(递归以及非递归实现)
  9. 在Mono 2.8上部署ASP.NET MVC 2
  10. fork与vfork的区别