CSDN博客

img hotjk

C++沉思录读书笔记(二)句柄类.上

发表于2004/7/6 15:24:00  1868人阅读

C++沉思录读书笔记(二)句柄类.上


延续 “C++沉思录读书笔记(一)代理类”
********
问题
********
创建代理将会复制所需要的对象,对某些类来说,复制的代价太大或者包含不能轻易被复制的资源。
如何在保持代理的多态行为的同时,避免复制对象的代价

class Point { //一个简单的类,没有指针成员的函数常常无需重写赋值操作符和复制构造函数
public:
 Point(): xval(0), yval(0) { }
 Point(int x, int y): xval(x), yval(y) { }
 int x() const { return xval; }
 int y() const { return yval; }
 Point& x(int xv) { xval = xv; return *this; }
 Point& y(int yv) { yval = yv; return *this; }
private:
 int xval, yval;
};

********
解决方案
********
@Handle类的轮廓
定义一个适当的Handle类,将Handle类绑定到它们所控制的对象上
要求:
1. Handle类应该创建和销毁对象
  创建自己的Point对象并把它赋给一个handle
  把创建Point的参数传给Handle
2. 通过Handle类访问Point对象
  重载Handle类的operator->操作符,暴露内部的Point对象(本文未采用这种方式)
  明确选择让Handle类支持那些Point操作

class Handle {
public:
 Handle();
 Handle(int, int);
 Handle(const Point&);
 Handle(const Handle&);
 Handle& operator=(const Handle&);
 ~Handle();
 int x() const;
 Handle& x(int);
 int y() const;
 Handle& y(int);
private:
 //...
};

@引用计数
因为允许多个句柄绑定到单个对象上,所以要使用引用计数确定多少个句柄绑定到同一个对象上,以便确定何时删除对象
引用计数不能是句柄的一部分,否则每个句柄必须知道跟它一起被绑定到同一个对象的其他所有句柄的位置(更不能使用static成员)
引用计数不能是对象的一部分,要求不重写已存在的Point对象

class UPoint { //用来存储引用计数和Point对象
private: //纯粹为了实现而设计,所有成员私有
 friend class Handle;
 Point p;
 int u;

 UPoint(): u(1) { } //UPoint对象总是随Handle类产生,因此缺省引用计数为1
 UPoint(int x, int y): p(x, y), u(1) { }
 UPoint(const Point& p0): p(p0), u(1) { }
};

class Handle {
public:
 Handle();
 Handle(int, int);
 Handle(const Point&);
 Handle(const Handle&);
 Handle& operator=(const Handle&);
 ~Handle();
 int x() const;
 Handle& x(int);
 int y() const;
 Handle& y(int);
private:
 UPoint* up; //新添加
};

@Handle类的实现
//构造函数
Handle::Handle(): up(new UPoint) { }
Handle::Handle(int x, int y): up(new UPoint(x, y)) { }
Handle::Handle(const Point& p): up(new UPoint(p)) { }

//析构函数
Handle::~Handle()
{
 if (up->u == 0)
  delete up;
}

//复制构造函数仅仅增加引用计数
Handle::Handle(const Handle& h): up(h.up) { ++up->u; }

//赋值操作符可能造成原左侧对象计数器为0
//先调用++可以保证左右两侧句柄引用同一个UPoint对象时也能工作
Handle& Handle::operator=(const Handle& h)
{
 ++h.up->u;
 if (--up->u == 0)
  delete up;
 return *this;
}

//简单的读函数
int Handle::x() const { return up->p.x(); }
int Handle::y() const { return up->p.y(); }

//复杂的写函数
/*
 句柄类在用户面前的行为
 Handle h(3,4) //原对象
 Handle h2 = h; //复制
 h2.x(5); //修改复制对象
 int n = h.x(); // 3 or 5?
*/

//指针语义:复制句柄类后,复制对象和原对象使用同一个UPoint对象

Handle& Handle::x(int x0)
{
 up->p.x(x0);
 return *this;
}

Handle& Handle::y(int y0)
{
 up->p.y(y0);
 return *this;
}

//值语义:复制句柄类后,复制对象和原对象不使用同一个UPoint对象
//在绝对必要的时候才进行对象复制,称为写时复制(copy on write),写时复制只是针对可变对象的一种优化技术

Handle& Handle::x(int x0)
{
 if (up->u != 1) {
  --up->u;
  up = new UPoint(up->p);
 }
 up->p.x(x0);
 return *this;
}

Handle& Handle::y(int y0)
{
 if (up->u != 1) {
  --up->u;
  up = new UPoint(up->p);
 }
 up->p.y(y0);
 return *this;
}

@图示
+--------+       +--------+       +--------+
| Handle |------>| UPoint |<>---->| Point  |
+--------+       +--------+       +--------+

0 0

相关博文

我的热门文章

img
取 消
img