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的麻烦.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/458669.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Swift调用Objective C的FrameWork

很多Github的库经过很多年的发展,源码都是OC写的,,所以,用Swift调用OC的库就是开发中难免遇到的的一个问题,本文以AFNetworking为例,讲解如何跨语言调用。 第一步 创建一个空的工程 注意,语言选…

显式(静态)调用: LIB + DLL + .H

1、编程时用ad.h,ad.lib,放在项目当前目录里2、在头文件中加入#include "ad.h"3、在Project Setting–>Link–>Object/library modules加入ad.lib执行时将ad.dll跟你的程序放在同一目录。 就可以直接调用dll中的函数了 当前目录 转载于:https://www.cnblogs.co…

接入支付宝出现交易订单处理失败,请稍后再试(ALI64)的错误

上次在接入支付宝的时候就碰到了交易订单处理失败,请稍后再试(ALI64)这样的错误,后来经过排查和总结,一般来讲这种问题都是公钥和私钥没有正确配置造成的。支付宝这边为了保证数据在传输时不被篡改,使用了r…

支付宝集成交互流程

交互流程 功能流程 流程说明(以Android平台为例): 第4步:调用支付接口:此消息就是本接口所描述的开发包提供的支付对象PayTask,将商户签名后的订单信息传进pay方法唤起支付宝收银台,订单格式具体…

VxLAN基础

转自:http://blog.csdn.net/freezgw1985/article/details/16354897 一 . 为什么需要Vxlan1. vlan的数量限制4096个vlan远不能满足大规模云计算数据中心的需求2. 物理网络基础设施的限制基于IP子网的区域划分限制了需要二层网络连通性的应用负载的部署3. TOR交换机MA…

C语言程序代码优化

我认为一个好的用于科学计算的程序代码应该:算法漂亮精妙,程序简洁易懂,运算快速,节省内存。这里有的地方是矛盾的,比如简洁vs易懂,时间vs空间,找个平衡吧。目前来看时间要比空间宝贵一些。写程…

如何在苹果官网下载旧版本的Xcode 方法

1 在百度里输入“苹果开发者中心“,进入以下页面。点击页面中的“Member Center" 2 出现登录界面。这是需要苹果开发者帐号的,没有帐号的可以选择“Create Apple ID”进行注册。已经注册的选择“Sign In"登录 3 页面跳转后,选择…

【转】android多分辨率适配

前一阶段开发android项目,由于客户要求进行多分辨率适配,能够支持国内主流的分辨率手机。因此经过了几次开发走了很多弯路,目前刚刚领略了android多分辨率适配的一些方法。 先介绍一下所走的弯路,由于android的布局文件存放在res的…

Java线程池介绍

根据摩尔定律(Moore’s law),集成电路晶体管的数量差不多每两年就会翻一倍。但是晶体管数量指数级的增长不一定会导致 CPU 性能的指数级增长。处理器制造商花了很多年来提高时钟频率和指令并行。在新一代的处理器上,单线程程序的执…

cocoa pods的安装与我遇到的问题

1.打开终端 终端输入 ruby -v 查看ruby的版本 打印代码: ruby 2.0.0p648 (2015-12-16 revision 53162) [universal.x86_64-darwin15] 2. 更换ruby镜像 终端输入如下命令(把Ruby镜像指向taobao,避免被墙,你懂得) a.移…

Implicit declaration of function 'NSFileTypeForHFSTypeCode' is invalid in C99

一般出现该问题是因为通过C调用了unix/linux 底层接口,所以需要调整c语言的编译选项,设置方法见下图:(根据实际情况选择相应的编译选项)

DebugView 调试入门

参考链接:http://blog.csdn.net/jiankunking/article/details/44984487 软件下载地址:点击打开链接 debugview 可以捕获程序中由TRACE(debug版本)和OutputDebugString输出的信息。支持Debug、Release模式编译的程序(即该软件捕获的是exe直接运…

DebugView使用笔记

1. 什么是DebugView? 它是Sysinternals公司的系列调试工具。可以捕获程序中由TRACE()和OutputDebugString输出的信息。 2. C需要完成哪些工作呢? 将打印的信息用OutputDebugString输出,示例: [cpp] view plaincopy #include "stdio.h&q…

QT之深入理解QThread

QT之深入理解QThread 理解QThread之前需要了解下QThread类,QThread拥有的资源如下(摘录于QT 5.1 帮助文档):在以上资源中,本文重点关注槽:start();信号:started()、finished()&#…

springMVC数据封装成POJO

springMVC把前台的数据封装为POJO与struts2的封装形式不同。struts2需要在控制器声明需封装的POJO,而springMVC不需要任何准备工作,只需在相应的方法的参数中加上需封装的POJO,当用户提交表单时,springMVC会根据表单中dom元素的na…

10.11 安装pod

原文地址:http://www.jianshu.com/p/5fc15906c53a 感谢。 更新升级10.11 cocoapods安装出问题最简单的解决方法 这是因为10.11把cocoapods直接干掉了 sudo gem install -n /usr/local/bin cocoapods 再加一句,完美解决 sudo xcode-select --switch /App…

JavaScript中的原型继承原理

在JavaScript当中,对象A如果要继承对象B的属性和方法,那么只要将对象B放到对象A的原型链上即可。而某个对象的原型链,就是由该对象开始,通过__proto__属性连接起来的一串对象。__proto__属性是JavaScript对象中的内部属性&#xf…

建模元件有哪些在MapleSim中

信号库:包含通用信号模块、布尔、控制器、离散信号模块、信号源、线性信号模块、非线性信号模块、时间离散信号模块、查询表、信号转换器、数学运算、关系元件、特殊信号模块,应用案例。 电子库:包含电阻、运算放大器、二极管、步进电机、模拟…

【C++】VS2010将写好的程序打包成安装文件发布

参考链接:http://blog.csdn.net/yongh701/article/details/51326142 我们可以将自己写好的VS2010程序打包成安装文件,给用户安装,具体步骤如下: 1、如下图,同样是新建一个项目,但是这次是新建一个其它项目…

01_jeecms建站

一、环境安装 JDK5TOMCAT5.5MYSQL5及以上http://www.jeecms.com/tutorial/index.jhtml参考环境安装篇二、解压文件安装包jeecms-v5zip,如图图1ROOT文件夹复制放到tomcat下的webapps文件夹(注:请先删除webapps下原有的默认ROOT文件夹)如不想部…