前面说的代理类,这个类能让我们在一个容器中存储类型不同但相互关联的对象。这种方法需要为每一个对象创建一个代理,并要将代理存储在容器中。创建代理将会复制所代理的对象,就像复制代理一样。
如果想避免这些复制该怎么做呢,通常采用一种叫做句柄的类(handle)
指针语义句柄
语义句柄拥有指针类似的功能。即一处改了,另一处也会被修改。
测试文件:
#include "stdafx.h"
#include <iostream>
#include "Point.h"
using namespace std;
int main()
{
Handle h(3, 4);
Handle h2 = h;
cout << "before h2.x(5):h.x=" << h.x() << endl;
h2.x(5);
cout << "after h2.x(5): h.x=" << h.x() << ", h2.x=" << h2.x() << endl;
return 0;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
实现效果:
before h2.x(5):h.x=3
after h2.x(5): h.x=5, h2.x=5
- 1
- 2
定义文件
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; }
~Point() {}
private:
int xval;
int yval;
};
class UPoint {
friend class Handle;
Point p;
int u;
UPoint() : u(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;
};
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
实现文件
#include "stdafx.h"
#include "Point.h"
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; }
Handle& Handle::operator=(const Handle& h)
{
++h.up->u;
if (--up->u == 0)
delete up;
up = h.up;
return *this;
}
int Handle::x() const { return up->p.x(); }
int Handle::y() const { return up->p.y(); }
Handle& Handle::x(int x0)
{
up->p.x(x0);
return *this;
}
Handle& Handle::y(int y0)
{
up->p.y(y0);
return *this;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
值语义句柄
值语义句柄拥有值类似的功能。即一处改了,另一处不会被修改。
测试文件:
#include "stdafx.h"
#include <iostream>
#include "Point.h"
using namespace std;
int main()
{
Handle h(3, 4);
Handle h2 = h;
cout << "before h2.x(5):h.x=" << h.x() << endl;
h2.x(5);
cout << "after h2.x(5): h.x=" << h.x() << ", h2.x=" << h2.x() << endl;
return 0;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
实现效果:
before h2.x(5):h.x=3
after h2.x(5): h.x=3, h2.x=5
- 1
- 2
如果需要值语义,就必须保证所改动的那个UPoint对象不能同时被任何其他的Handle所引用。这倒不难,只要看看引用计数即可。如果是1,则说明handle是唯一一个使用该UPoint对象的句柄;其他情况下,就必须复制UPoint对象,使得引用计数变成1.
修改代码:
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;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
这一技术通常称为copy on write(写时复制)。其优点是只有在绝对必要时复制,从而避免不必要的复制,而且额外开销也只有一丁点儿。在涉及值语义的句柄的类库中,这一技术经常用到。
优化
由于代码
if (up->u != 1) {
--up->u;
up = new UPoint(up->p);
}
- 1
- 2
- 3
- 4
面要在每一个改变UPoint对象的函数中重复使用,这暗示我们可以设计一个private成员函数对前面进行改写
void Handle::copy_on_write()
{
if (up->u != 1) {
--up->u;
up = new UPoint(up->p);
}
}
Handle& Handle::x(int x0)
{
copy_on_write();
up->p.x(x0);
return *this;
}
Handle& Handle::y(int y0)
{
copy_on_write();
up->p.y(y0);
return *this;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
附最终的代码
Point.h
#pragma once
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; }
~Point() {}
private:
int xval;
int yval;
};
class UPoint {
friend class Handle;
Point p;
int u;
UPoint() : u(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:
void copy_on_write();
private:
UPoint * up;
};
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
Point.cpp
#include "stdafx.h"
#include "Point.h"
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; }
Handle& Handle::operator=(const Handle& h)
{
++h.up->u;
if (--up->u == 0)
delete up;
up = h.up;
return *this;
}
int Handle::x() const { return up->p.x(); }
int Handle::y() const { return up->p.y(); }
void Handle::copy_on_write()
{
if (up->u != 1) {
--up->u;
up = new UPoint(up->p);
}
}
Handle& Handle::x(int x0)
{
copy_on_write();
up->p.x(x0);
return *this;
}
Handle& Handle::y(int y0)
{
copy_on_write();
up->p.y(y0);
return *this;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
<link href="https://csdnimg.cn/release/phoenix/mdeditor/markdown_views-8cccb36679.css" rel="stylesheet">
</div>