zoukankan      html  css  js  c++  java
  • 句柄类的实现:分割引用计数和原数据

    句柄类的实现:分割引用计数和原数据

             ——《C++沉思录》第7章 句柄:第二部分

             《句柄类》中,介绍了一种句柄的简单实现,其基本结构就是定义了三个类:Point类、Handle类、UPoint类。其中Point为实际的原数据类,Handle为句柄类,UPoint为实际操作的数据类,其成员除了Point的一个对象外还有个int型的技术。

             这里我们先将UPoint中的两个成员分割,之后再将int型技术进行封装成一个标准的引用技术类UseCount。

           1.Pointint

             删除UPoint类,并将Handle中的UPoint* up指针删除,添加Point和int指针。

    #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; }
    };
    
    // 句柄类
    class Handle
    {
    private:
        // 更改:删除原来的 UPoint* up 指针
        // 添加指向Point的指针和执行int的指针
        Point* p; // 指向原数据
        int*   u; // 指向引用计数
    
    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 << *u << endl;
    }
    
    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& p0) : u(new int(1)), p(new Point(p0)) {}
    
    Handle::Handle(const Handle& h) : u(h.u), p(h.p) { ++*u; }
    
    Handle::~Handle()
    {
        if (--*u == 0)
        {
            // 两个delete
            delete u;
            delete p;
        }
    }
    
    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)和Handle& Handle::y(int)的实现有两种方式:
    // 指针语义和值语义
    // 其中值语义的实现方式称作为写时赋值(copy on write)
    
    // 指针语义
    Handle& Handle::x(int x0)
    {
        p->x(x0);
        return *this;
    }
    
    Handle& Handle::y(int y0)
    {
        p->y(y0);
        return *this;
    }
    
    //// 值语义
    //Handle& Handle::x(int x0)
    //{
    //    if (*u > 1)
    //    {
    //        --*u;
    //        u = new int(1);
    //        p = new Point(*p);
    //    }
    //    p->x(x0);
    //    return *this;
    //}
    //
    //Handle& Handle::y(int y0)
    //{
    //    if (*u > 1)
    //    {
    //        --*u;
    //        u = new int(1);
    //        p = new Point(*p);
    //    }
    //    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;
    }

           2.抽象引用计数——UseCount

             将int型的计数抽象化,使其具备自身赋值、拷贝功能。将一些实现从Handle中抽离出来。

             具体说明可以详见代码中的注释。

    #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; }
    };
    
    class UseCount
    {
    private:
        int* p;
    
    public:
        UseCount();
        UseCount(const UseCount&);
        ~UseCount();
    
        // 返回p指向的计数值,用于测试
        int val() const;
    
        // 检测原数据是否指服务于一个句柄
        bool only() const;
    
        // 增加一个函数用来代替operator=函数
        // 该函数在Handle的operator=中调用
        bool reattach(const UseCount&);
    
    private:
        // 将operator=私有化
        UseCount& operator = (const UseCount&);
    
    public:
        // 如果引用计数为1,则直接修改
        // 如果大于1,则new一个新的引用计数,在Handle写入时new一个新的原数据
        // 该函数用于实现值语义,写时复制
        bool makeonly();
    };
    
    UseCount::UseCount() : p(new int(1)) {}
    
    UseCount::UseCount(const UseCount& u) : p(u.p) { ++*p; }
    
    UseCount::~UseCount()
    {
        if (--*p == 0)
        {
            delete p;
        }
    }
    
    int UseCount::val() const
    {
        return *p;
    }
    
    bool UseCount::only() const
    {
        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;
    }
    
    // 句柄类
    class Handle
    {
    private:
        Point* p; // 指向原数据
        // 将原来的int* u抽象化为UseCount u
        UseCount u;
    
    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 << u.val() << endl;
    }
    
    // 由于UseCount类有自身的构造函数,所以Handle构造函数的实现部分可以不用涉及u的构造
    Handle::Handle() : p(new Point) {}
    
    Handle::Handle(int x, int y) : p(new Point(x, y)) {}
    
    Handle::Handle(const Point& p0) : p(new Point(p0)) {}
    
    Handle::Handle(const Handle& h) : u(h.u), p(h.p) {}
    
    Handle::~Handle()
    {
        if (u.only())
        {
            delete p;
        }
    }
    
    Handle& Handle::operator = (const Handle& h)
    {
        // 这里忽略对引用计数的操作,因为已经在UseCount的reattach中操作完毕
        if (u.reattach(h.u))
        {
            // 如果reattach返回true,说明u这个引用计数值原来为1,所以赋值需要将原数据*p删除
            delete p;
        }
        p = h.p;
        return *this;
    }
    
    int Handle::x() const { return p->x(); }
    int Handle::y() const { return p->y(); }
    
    // 对Handle& Handle::x(int)和Handle& Handle::y(int)的实现有两种方式:
    // 指针语义和值语义
    // 其中值语义的实现方式称作为写时赋值(copy on write)
    
    //// 指针语义
    //Handle& Handle::x(int x0)
    //{
    //    p->x(x0);
    //    return *this;
    //}
    //
    //Handle& Handle::y(int y0)
    //{
    //    p->y(y0);
    //    return *this;
    //}
    
    // 值语义
    Handle& Handle::x(int x0)
    {
        if (u.makeonly())
        {
            p = new Point(*p);
        }
        p->x(x0);
        return *this;
    }
    
    Handle& Handle::y(int y0)
    {
        if (u.makeonly())
        {
            p = new Point(*p);
        }
        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;
    }

           3.总结

             上文《句柄类》和本文,我们一共介绍了三种句柄类的实现方式,第一种是将原数据和引用计数封装为一个类,进而组合为句柄类;第二种是将原数据和引用计数分离,各自为政,其中引用计数的赋值、拷贝操作是在句柄类中完成的;第三种方式是将引用计数进行抽象化,引用计数的赋值、拷贝操作都在其自身实现中完成,继而被句柄类调用。

  • 相关阅读:
    公司财务(书籍学习过程总结)
    职场心理学-心理学第一天(非原创)
    (原创干货)自身管理-日常思考实战框架学习第八天
    (原创干货)融资、路演-日常思考实战框架学习第七天
    (原创干货)理财、投资-日常思考实战框架学习第七天
    (原创干货)理财、投资-日常思考实战框架学习第六天
    (原创干货)公司金融-日常思考实战框架学习第五天
    (原创干货)沟通、演讲-日常思考实战框架学习第四天
    虚拟机中给linux 系统添加硬盘以后,进行分区挂载
    基于Xshell使用密钥方式连接远程主机
  • 原文地址:https://www.cnblogs.com/unixfy/p/3460262.html
Copyright © 2011-2022 走看看