C++沉思录-第7章 句柄二 引用计数的分离

第六章的句柄,通过UPoint类封Point实现句柄的绑定。
UPoint类的使用只是为了实现引用计数,因此,本章的任务是不再实现额外的UPoint,只将引用计数进行单独考量。

简单的引用计数

句柄:第二部分,分离引用计数
将引用计数从数据中分离出来,把引用计数放入它自己的对象中。

引用计数的分离

指针语义实现

先上Point类代码:

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

把引用计数从Point中分离出来的实现方法:

class Handle {
public:
        // 和前面一样
private:
    Point* p;
    int* u; //指向引用计数的指针
}

大家发现,类UPoint消失了,不再有指向UPoint类的指针了。我们用一个int的指针表示引用计数。
使用Point*而不是UPoint*是很重要的,因为正是Point*使我们不仅能够将一个Handle绑定到一个Point,还能将其绑定到一个继承自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 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:
    Point * p;
    int * u;
};

实现文件.cpp

#include "stdafx.h"
#include "Point.h"


Handle::Handle() : u(new int(1)), p(new Point()) {}
Handle::Handle(int x, int y) : u(new int(1)), p(new Point(x, y)) {}
Handle::Handle(const Point& p) : u(new int(1)), p(new Point()) {}
Handle::~Handle()
{
    if (--*u == 0) {
        delete u;
        delete p;
    }       
}
Handle::Handle(const Handle& h) :u(h.u), p(h.p) { ++*u; }
Handle& Handle::operator=(const Handle& h)
{
    ++*h.u;
    if (--*u == 0) {
        delete u;
        delete p;
    }
    u = h.u;
    p = h.p;
    return *this;
}

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

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

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

最后附上测试代码:

// ConsoleApplication2.cpp : 定义控制台应用程序的入口点。
//

#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;
}
/* 运行结果:
before h2.x(5):h.x=3
after h2.x(5): h.x=5, h2.x=5
请按任意键继续. . .
*/

值语义的实现

由运行结果可以看出,以上实现的是指针语义的句柄,如果要实现值语义的句柄,就需要用到copy_on_write技术,实现起来也很简单
首先实现copy_on_write函数

void Handle::copy_on_write()
{
    if (*u != 1) {
        --*u;
        p = new Point();
        u = new int(1);
    }
}

然后在需要改变x或y的地方增加对copy_on_write的调用

Handle& Handle::x(int x0)
{
    copy_on_write(); // 新增调用
    p->x(x0);
    return *this;
}

Handle& Handle::y(int y0)
{
    copy_on_write(); // 新增调用
    p->y(y0);
    return *this;
}

最后附测试代码和运行结果

// ConsoleApplication2.cpp : 定义控制台应用程序的入口点。
//

#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;
}
/* 运行结果:
before h2.x(5):h.x=3
after h2.x(5): h.x=3, h2.x=5
请按任意键继续. . .
*/

对引用计数的抽象

我们已经知道引用计数通常从1开始,这就告诉我们缺省构造函数应该为:

UseCount::UseCount() : p(new int(1)) {}

我们也知道从一个UseCount构造另一个会使两者都指向相同的计数器,并递增计数器的值:

UseCount::UseCount(const UseCount& u) : p(u.p) { ++*p; }

销毁一个UseCount会使计数器的值减1,删除计数器则会返回0

UseCount::~UseCount() {
    if (--*p == 0)
        delete p;
}

现在我们可以重写Handle类了:

class Handle {
pulbic:
    // 和前面的一样
private:
    Point* p;
    UseCount u;
}

由于抽象的逻辑稍微复杂,这儿不细描述,稍后补上,直接上抽象后的代码:

#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 UseCount {
public:
    UseCount();
    UseCount(const UseCount&);

    ~UseCount();
public:
    bool only();
    bool makeonly();
    bool reattach(const UseCount&);
private:
    UseCount& operator=(const UseCount&);
private:
    int* p;
};
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:
    Point * p;
    UseCount u;
};

实现文件.cpp

#include "stdafx.h"
#include "Point.h"


UseCount::UseCount() : p(new int(1)) {}
UseCount::UseCount(const UseCount& u) : p(u.p) { ++*p; }
UseCount::~UseCount() {
    if (--*p == 0)
        delete p;
}
bool UseCount::only() { return *p == 1; }
bool UseCount::reattach(const UseCount& u)
{
    ++*u.p;
    if (--*p == 0) {
        delete p;
        p = u.p;
        return true;
    }
    p = u.p;
    return false;
}

bool UseCount::makeonly()
{
    if (*p == 1)
        return false;
    --*p;
    p = new int(1);
    return true;
}
Handle::Handle() : p(new Point()) {}
Handle::Handle(int x, int y) : p(new Point(x, y)) {}
Handle::Handle(const Point& p) : p(new Point()) {}
Handle::~Handle()
{
    if (u.only()) {
        delete p;
    }       
}
Handle::Handle(const Handle& h) :u(h.u), p(h.p) { }
Handle& Handle::operator=(const Handle& h)
{
    if (u.reattach(h.u))
        delete p;
    p = h.p;
    return *this;
}

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


void Handle::copy_on_write()
{
    if (u.makeonly())
        p = new Point(*p);
}

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

Handle& Handle::y(int y0)
{
    copy_on_write();
    p->y(y0);
    return *this;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

永远的麦田

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值