句柄类

句柄类

         ——《C++沉思录》第六章 句柄:第一部分

         三个类:

         Point:主体类,表示实际的数据

         Handle:句柄类,用来引用代理主体类

         UPoint:对Point的封装,增加了一个use count成员,用来记录主体类对象被引用代理的次数。该类完全可以省略,但是添加此类的好处是更便于管理。

         对Handle的拷贝构造函数和赋值运算符的实现是通过对UPoint对象的use count修改来完成的。Handle中有两个写函数,有两种实现方式:指针语义和值语义,这里涉及了一项技术称作写时赋值(copy on write)。

         具体代码如下:

// 句柄类
#include <iostream>
using namespace std;

class Point
{
private:
    int xval;
    int yval;

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; }
};

// use count class
class UPoint
{
private:
    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
{
private:
    UPoint* up;

public:
    Handle();
    Handle(int, int);
    Handle(const Point&);
    Handle(const Handle&);
    Handle& operator = (const Handle&);
    ~Handle();

    int x() const;
    int y() const;

    Handle& x(int);
    Handle& y(int);

    void test() const;
};

void Handle::test() const
{
    cout << up->u << endl;
}

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;

    // 对于operator=的操作也可以采用另外一种方法:
    // 先检测是否是自赋值,如果是,则不进行操作,直接返回*this
    // 如果不是,则--up->u,然后++h.up->u
}

int Handle::x() const { return up->p.x(); }
int Handle::y() const { return up->p.y(); }

// 对Handle& Handle::x(int)和Handle& Handle::y(int)的实现有两种方式:
// 指针语义和值语义
// 其中值语义的实现方式称作为写时赋值(copy on write)

// 指针语义
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->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;
//}

int main()
{
    Point p1;
    Handle* ph1 = new Handle(p1);

    ph1->test();

    Handle* ph2 = new Handle(*ph1);

    ph1->test();
    ph2->test();

    delete ph1;

    ph2->test();
    
    return 0;
}

原文地址:https://www.cnblogs.com/unixfy/p/3453728.html