1、在【C++沉思录】代理类中,使用了代理类,存在问题:
a、代理复制,每次创建一个副本,这个开销有可能很大
b、有些对象不能轻易创建副本,比如文件
2、怎么解决这个问题?
使用引用计数句柄,对动态资源封装,句柄包含指针,多个句柄可以指向同一个对象。复制的时候,只是复制句柄的指针。
3、使用引用计数句柄,是为了避免不必要的对象复制,因此我们要知道有多少个句柄绑定到当前对象,也就是引用计数,
这样才能确定何时可以释放资源。
4、需要注意的是:引用计数不能是句柄的一部分,如果怎么做,当前句柄必须知道指向同一个对象的其他句柄,引用计数也要保持一致。
同时,引用计数不能成为对象的一部分,如果这样做,要求我们重写已经存在的对象类。
5、以Point类为例说明,解决办法是:增加一个新的类UPoint,包含Point对象和引用计数u,如下:
class Point
{
public:
Point():_x(0),_y(0){}
Point(int x,int y):_x(x),_y(y){}
Point(const Point& rhs):_x(rhs._x),_y(rhs._y){}

Point& SetX(int x)
{
_x = x;
return *this;
}

int GetX()
{
return _x;
}

Point& SetY(int y)
{
_y = y;
return *this;
}

int GetY()
{
return _y;
}

private:
int _x;
int _y;
};

#include "point.h"

// UPoint的目的是对Point和引用计数封装,用户是不可见的
class UPoint
{
friend class Handle_1;

private:
Point p;
int u;

UPoint():u(1){}

UPoint(int x,int y)
{
p.SetX(x);
p.SetY(y);
u = 1;
}

UPoint(const Point& rhs)
{
p = rhs;
u = 1;
}
};

6、现在考虑Handle_1的实现细节,
#include "u_point.h"

class Handle_1
{
public:
Handle_1():_up(new UPoint){}

Handle_1(int x,int y):_up(new UPoint(x,y)){}

Handle_1(const Point& rhs):_up(new UPoint(rhs)){}

~Handle_1()
{
subRef();
}

// copy构造,复制指针,增加引用
Handle_1(const Handle_1& rhs)
{
addRef(rhs._up);
}

// copy赋值,左边减少引用计数,判断是否delete,右边增加引用计数,考虑自我赋值
Handle_1& operator=(const Handle_1& rhs)
{
if(this != &rhs)
{
subRef();
addRef(rhs._up);
}

return * this;
}

int GetX()
{
return _up->p.GetX();
}

int GetY()
{
return _up->p.GetY();
}

Handle_1& SetX(int x)
{
_up->p.SetX(x);
return *this;
}

Handle_1& SetY(int y)
{
_up->p.SetY(y);
return *this;
}

private:
void addRef(UPoint* up) // 复制指针,增加引用
{
_up = up;
++_up->u;
}

void subRef() // 减少引用,判断是否delete
{
if(--_up->u == 0)
{
delete _up;
}
}

private:
UPoint* _up;
};

7、考虑下面的情况,
Handle_1 h1(3,4);
Handle_1 h2(h1);
h2.SetX(5);
int dd = h1.GetX();
dd的值是5,也就是说,多个句柄指向同一个对象,避免了不必要的对象复制,实现的是 指针语义。但是对于上面的情况,往往不是用户所期望的,
怎么解决这个问题?
8、使用写时拷贝,每次修改的时候重新创建一个对象。也就是说,修改的时候变成值语义,原对象h1是不可变对象,使用h2修改,会导致重新创建一个对象。
如下:
Handle_1& SetX(int x)
{
//_up->p.SetX(x);
if(_up->u == 1) // 当前是唯一的引用
{
_up->p.SetX(x);
}
else
{
--_up->u;
_up = new UPoint(x,_up->p.GetY());
}
return *this;
}

Handle_1& SetY(int y)
{
//_up->p.SetY(y);
if(_up->u == 1) // 当前是唯一的引用
{
_up->p.SetY(y);
}
else
{
--_up->u;
_up = new UPoint(_up->p.GetX(),y);
}
return *this;
}

【C++沉思录】句柄1的更多相关文章

  1. 【C++沉思录】句柄2

    1.[C++沉思录]句柄1 存在问题: 句柄为了绑定到Point的对象上,必须定义一个辅助类UPoint,如果要求句柄绑定到Point的子类上,那就存在问题了.2.有没有更简单的办法呢? 句柄使用Po ...

  2. 生活沉思录 via 哲理小故事(四)

    1.围墙里的墓碑 第一次世界大战期间,驻守意大利某小镇的年轻军官结识了镇上的牧师.虽然军官信仰信教,而牧师是天主教牧师,但两人一见如故. 军官在一次执行任务中身负重伤,弥留之际嘱托牧师无论如何要把自己 ...

  3. 生活沉思录 via 哲理小故事

    本文转载:http://www.cnblogs.com/willick/p/3174803.html 1.小托蒂的悲剧 意大利小男孩托蒂,有一只十分奇怪的眼睛,因为从生理上看,这是一只完全正常的眼睛, ...

  4. 生活沉思录 via 哲理小故事(一)

    1.小托蒂的悲剧 意大利小男孩托蒂,有一只十分奇怪的眼睛,因为从生理上看,这是一只完全正常的眼睛,但却是失明的. 原来,托蒂刚出生时,这只眼睛轻度感染,曾用绷带缠了两个星期.这对常人来说几乎没有人任何 ...

  5. Atitit。 沉思录 与it软件开发管理中的总结 读后感

    Atitit. 沉思录 与it软件开发管理中的总结 读后感 1. <沉思录>,古罗马唯一一位哲学家皇帝马可·奥勒留所著 2 2. 沉思录与it软件开发管理中的总结 2 2.1. 要有自己的 ...

  6. c++沉思录 学习笔记 第六章 句柄(引用计数指针雏形?)

    一个简单的point坐标类 class Point {public: Point():xval(0),yval(0){} Point(int x,int y):xval(x),yval(y){} in ...

  7. c++学习书籍推荐《C++沉思录》下载

    百度云及其他网盘下载地址:点我 编辑推荐 经典C++图书,应广大读者的强烈要求再版 目录 第0章 序幕第一篇 动机第1章 为什么我用C++第2章 为什么用C++工作第3章 生活在现实世界中 第二篇 类 ...

  8. C++模板沉思录(上)

    花下猫语: 在我们读者群里,最近出现了比较多关于 C++ 的讨论,还兴起了一股学习 C++ 的风气.樱雨楼小姐姐对 C++ 的模板深有研究,系统地梳理成了一篇近 4 万字的文章!本文是上篇,分享给大家 ...

  9. C++模板沉思录

    0 论抽象--前言 故事要从一个看起来非常简单的功能开始: 请计算两个数的和. 如果你对Python很熟悉,你一定会觉得:"哇!这太简单了!",然后写出以下代码: def Plus ...

随机推荐

  1. Hibernate框架—简介

    ORM对象/关系数据库映射 ORM全称Object/Relation Mapping,对象/关系数据库映射,可以理解成一种规范.该框架的基本特征:完成面向对象的编程语言到关系数据库之间的映射. ORM ...

  2. linux 下 jdk+tomcat+mysql 的 jsp 环境搭建

    JDK 在 linux 下安装 1.          把安装文件放在 /opt 下,并执行 [root@localhost opt]# ./jdk-1_5_0_06-linux-i586.bin 并 ...

  3. 【kd-tree】bzoj3053 The Closest M Points

    同p2626.由于K比较小,所以不必用堆. #include<cstdio> #include<cstring> #include<cmath> #include& ...

  4. HTML5服务器端推送事件 解决PHP微信墙推送问题

    问题描述 以前的文章中<PHP微信墙制作,开源>已经用PHP搭建了一个微信墙获取信息的服务器,然后我就在想推送技术应该怎么解决,上一篇已经用了.NET 的signalr做了一个微信墙,PH ...

  5. EmberJs之3W

    写在前面 最近比较忙,换了新工作还要学习很多全新的技术栈,并给自己找了很多借口来不去坚持写博客.常常具有讽刺意味的是,更多剩下的时间并没有利用而更多的是白白浪费,也许这就是青春吧,挥霍吧,这不是我想要 ...

  6. 傻逼Eclipse笔记

    Eclipse 这么傻逼的工具,还有人用,真是奇了怪了. Invalid project description 我想打开SVN 的代码 ,别让我拷到别的地方,怎么破? 正确答案是: 删除 Eclip ...

  7. node-webkit教程(11)Platform Service之shell

    node-webkit教程(11)Platform Service之shell 文/玄魂 目录 node-webkit教程(10)Platform Service之shell 前言 11.1  She ...

  8. [芯片] 3、接口技术·实验三·可编程并行接口8255A

    目录 一.实验目的和要求 二.实验原理与背景 2-1.8255A简介 2-2.8255A编程 三.实验具体的内容 3-1.8255方式0实验1 3-2.8255方式0实验2 3-3.8255方式1输出 ...

  9. [J2ME] 基本框架框架

    import javax.microedition.lcdui.Command; import javax.microedition.lcdui.CommandListener; import jav ...

  10. C++ 类

    <C++ Primer 4th>读书笔记 在 C++ 中,用类来定义自己的抽象数据类型(abstract data types).通过定义类型来对应所要解决的问题中的各种概念.最简单地说, ...