『C++沈思録』-第七章-ハンドル:第二部分

2620 ワード

第6章では、クラスにハンドルと参照カウントを追加する技術について述べ、参照カウントを値制御することでクラスのオブジェクトを効率的に「コピー」することができる.この技術には明らかな欠点がある:ハンドルをクラスTのオブジェクトにバインドするためには、タイプTを持つメンバーの新しいクラスを定義する必要がある.
分離参照数:
class Handle
{
public:
    Handle(): u(new int(1)), p(new Point) {}
    Handle(int x, int y): u(new int(1)), p(new Point(x, y)) {}
    Handle(const Point& p0): u(new int(1)), p(new Point(p0)) {}
    Handle(const Handle& h): u(h.u), p(h.p)  {++*u;}
    Handle& operator=(const Handle& h)
    {
        ++*h.u;
        if (--*u == 0)
        {
            delete u;
            u = NULL;
            delete p;
            p = NULL;
        }
        u = h.u;
        p = h.p;
        return *this;
    }
    ~Handle()
    {
        if (--*u == 0)
        {
            delete u;
            u = NULL;
            delete p;
            p = NULL;
        }
    }
private:
    Point* p;
    int* u; //         
};

参照数の抽象化:
class UseCount
{
public:
    UseCount():count(new int(1)){}
    UseCount(const UseCount& uc):count(uc.count){ ++*count;}
    UseCount& operator=(const UseCount &u)
    {
       reattach(u);
       return *this;
    }
    ~UseCount()
    {
       if (--*count == 0)
       {
           delete count;
           count == NULL;
       }
    }
    bool only() { return *count == 1;} //           ,         
    bool reattach(const UseCount &u)  //    ,    
    {
      ++*u.count;
      if (--*u.count == 0)
      {
          delete count;
          count = u.count;
          return true;
      }
      count = u.count;
      return false;
    }
    bool makeonly()                  //      ,        
    {
      if (*count == 1)
          return false;
      --*count;
      count = new int(1);
      return true;
    }
private:
    int *count;//  
};
class Handle
{
public:
    //          UsrCount       ,       
    Handle(): p(new Point) {}
    Handle(int x, int y): p(new Point(x, y)) {}
    Handle(const Point& p0): p(new Point(p0)) {}
    Handle(const Handle& h): u(h.u), p(h.p) {}
    Handle& operator=(const Handle& h)
    {
        if (u.reattach(h.u))
        {
            delete p;
        }
        p = h.p;
        return *this;
    }
    ~Handle()
    {
        if (u->only())
        {
            delete p;
            p = NULL;
        }
    }
    int x() const {return p->x();}
    Handle& x(int x0)
    {
        if (y.makeonly())
        {
            p = new Point(*p);
        }
        p->x(x0);
        return *this;
    }
private:
    Point* p;
    UseCount* u; //         
};