創建代理會復制所代理的對象,如何避免這些復制呢?
可以通過句柄(handle)類來實現。句柄類和智能指針有點類似,通過重載句柄類的*和->操作符,可將句柄類改造稱為智能指針。
從效果上來說,handle就是一種只包含單個對象的容器,它通過允許多個handle對象指向同一個對象來避免復制。
定義句柄類,我們還需要新定義一個類來容納被引用類對象的引用計數和被引用類對象本身。
示例代碼如下
#include <iostream>
using namespace std;
class Point
{
private:
int xval, yval;
public:
Point() : xval(0), yval(0)
{
cout << "Point" << endl;
}
Point(int x, int y) : xval(x), yval(y)
{
cout << "Point" << endl;
}
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()
{
cout << "~Point" << endl;
}
};
class UPoint //這個類對用戶來說是不可見的, 就是一個間接層
{
friend class Handle;
Point p; //Point 對象
int u; //計數器
UPoint():u(1) //提供所有的point的構造方式
{
cout << "UPoint::" << u << endl;
}
UPoint(int x, int y):p(x, y), u(1)
{
cout << "UPoint::" << u << endl;
}
UPoint(const Point &p0) : p(p0), u(1)
{
cout << "UPoint::" << u << endl;
}
~UPoint()
{
cout << "~UPoint::" << u << endl;
}
};
class Handle
{
private:
UPoint *up; //和間接層UPoint打交道了
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);
};
Handle::Handle():up(new UPoint)
{
cout << "Handle::" <<up->u << endl;
}
Handle::Handle(int x, int y):up(new UPoint(x, y)) //按創建Point的方式構造handle,handle->UPoint->Point
{
cout << "Handle::" <<up->u << endl;
}
Handle::Handle(const Point &p):up(new UPoint(p)) //創建Point的副本
{
cout << "Handle::" <<up->u << endl;
}
Handle::~Handle()
{
if(--up->u == 0)
{
cout << "~Handle::" <<up->u << endl;
delete up;
}
else
{
cout << "~Handle::" <<up->u << endl;
}
}
Handle::Handle(const Handle &h):up(h.up)
{
++up->u; //此處復制的是handle,但是底層的point對象並未復制,只是引用計數加1
cout << "Handle::" <<up->u << endl;
}
Handle& Handle::operator=(const Handle &h)
{
++h.up->u; //右邊的對象引用計數加1,左邊的減1
if(--up->u == 0)
delete up;
up = h.up;
cout << "Handle::" <<up->u << endl;
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;
}
/*
Handle& Handle::x(int x0)//假設句柄為值語義(寫時復制)
{
if(up->p != 1)
{
--up->u;
up = new UPoint(up->p);
}
up->p.x(x0);
return *this;
}
Handle& Handle::y(int y0)
{
if(up->p != 1)
{
--up->u;
up = new UPoint(up->p);
}
up->p.y(y0);
return *this;
}
*/
void f(Handle h) //測試函數,復制handle,但未復制Point
{
cout << h.x() << h.y() << endl;
}
int main()
{
Handle h(3,5);
cout << h.x() << h.y() << endl;
f(h);
Point o(10,9);
Handle a(o);
Handle b(a);
return 0;
}
作者 yucan1001