龙盟编程博客 | 无障碍搜索 | 云盘搜索神器
快速搜索
主页 > 软件开发 > C/C++开发 >

More Effective C++之引用计数

时间:2009-12-22 15:42来源:未知 作者:admin 点击:
分享到:
Reference counting让我想起了Java,当假如想用C++来实现Java的能力的话,那Reference counting必不可少。Reference counting可以节省程序的运行成本,大量的构造、析构、分配、释放和拷贝的代价被

  Reference counting让我想起了Java,当假如想用C++来实现Java的能力的话,那Reference counting必不可少。Reference counting可以节省程序的运行成本,大量的构造、析构、分配、释放和拷贝的代价被省略。

  

  实现

  

  

classRCObject

  {

   public:

  RCObject():refCount(0),shareable(true){}

  RCObject(constRCObject&):refCount(0),shareable(true){}

  RCObject& operator=(constRCObject& rhs){return *this;}

  virtual ~RCObject()=0;

  void AddReference(){++refCount;}

  void RemoveReference(){if (--refCount == 0) deletethis;}

  

  void markUnshareable(){shareable = false;}

  bool isShareable() const{returnshareable;}

  bool isShared() const {returnrefCount > 1;}

   private:

  int refCount;

  bool shareable;

  };

  RCObject::~RCObject(){}

  

  template

  class RCPtr

  {

   public:

  RCPtr(T* realPtr = 0):pointee(realPtr){init();}

  RCPtr(constRCPtr& rhs):pointee(rhs.pointee){init();}

  ~RCPtr(){if (pointee) pointee->RemoveReference();}

  RCPtr& operator = (constRCPtr& rhs)

  {

   if (pointee!=rhs.pointee)

   {

  if (pointee)

   pointee->RemoveReference();

   pointee = rhs.pointee;

   init();

   }

   return *this;

  }

  T* operator->() const { returnpointee;}

  T& operator*() const{return *pointee;}

   private:

  T* pointee;

  void init()

  {

   if (pointee == 0)

  return;

   if (pointee->isShareable() == false)

  pointee = newT(*pointee);

   pointee->AddReference();

  }

  };

  

  class String

  {

   public:

  String(const char* value = ""):value(newStringValue(value)){}

  const char& operator[](intnIndex) const

  {

   return value->data[nIndex];

  }

  char& operator[](intnIndex)

  {

   if (value->isShared())

  value = newStringValue(value->data);

  value->markUnshareable();

  returnvalue->data[nIndex];

  }

   protected:

   private:

  strUCt StringValue:publicRCObject

  {

   char* data;

   String Value(constchar* initValue)

   {

  init(initValue);

   }

   String Value(constStringValue& rhs)

   {

  init(rhs.data);

   }

   void init(constchar * initValue)

   {

  data = newchar[strlen(initValue) + 1];

  strcpy(data,initValue);

   }

   ~String Value()

   {

  delete [] data;

   }

  };

  RCPtr value;

  };

  这是Meyers给出的String的实现,然而我的观点是假如没有非凡的必要的话,对stirng最好不要使用引用计数,因为在多线程程序中同步的代价要大于引用计数本身的好处,得不偿失。

  

  假如StringValue是一个现成的类,无法修改它的实现,那怎么办?没关系可以用委托,下面是一个典型的实现:

  

  

  

classRCObject

  {

   public:

  RCObject():refCount(0),shareable(true){}

  RCObject(constRCObject&):refCount(0),shareable(true){}

  RCObject& operator=(constRCObject& rhs){return *this;}

  virtual ~RCObject()=0;

  void AddReference(){++refCount;}

  void RemoveReference(){if (--refCount == 0) deletethis;}

  

  void markUnshareable(){shareable = false;}

  bool isShareable() const{returnshareable;}

  bool isShared() const {returnrefCount > 1;}

   private:

  int refCount;

  bool shareable;

  };

  RCObject::~RCObject(){}

  

  template

  class RCIPtr

  {

   public:

  RCIPtr(T* realPtr = 0):counter(new CountHolder)

  {

   counter->pointee = realPtr;

   init();

  }

  RCIPtr(constRCIPtr& rhs):counter(rhs.counter)

  {

   init();

  }

  ~RCIPtr()

  {

   counter->RemoveReference();

  }

  RCIPtr& operator = (constRCIPtr& rhs)

  {

   if (counter != rhs.counter)

   {

  counter->RemoveReference();

  counter = rhs.counter;

  init();

   }

   return *this;

  }

  constT* operator->()const

  {

   returncounter->pointee;

  }

  T* operator->()

  {

   makeCopy();

   returncounter->pointee;

  }

  constT& operator*() const

  {

   return *(counter->pointee);

  }

  T& operator*()

  {

   makeCopy();

   return *(counter->pointee);

  }

   private:

  struct CountHolder:publicRCObject

  {

   ~Count Holder(){deletepointee;}

   T* pointee;

  };

  Count Holder* counter;

  void init()

  { 

   if (counter->isShareable() == false)

   {

  T* oldValue = counter->pointee;

  counter = newCountHolder;

  counter->pointee = newT(*oldValue);

   }

   counter->AddReference();

  }

  void makeCopy()

  {

   if (counter->isShared())

   {

  T* oldValue = counter->pointee;

  counter->RemoveReference();

  counter = newCountHolder;

  counter->pointee = newT(*oldValue);

  counter->AddReference();

   }

  }

   };

   class Widget

   {

  public:

   Widget(intSize){}

   Widget(constWidget& rhs){}

   ~Widget(){}

   Widget operator=(const Widget& rhs){}

   void doThis(){printf("doThis()

");return;}

   int showThat() const{printf("showThat()

"); return 0;}

  protected:

  private:

   inti;

   };

  

   class RCWidget

   {

  public:

   RCWidget(intsize):value(newWidget(size)){}

   void doThis(){value->doThis();}

   int showThat()const {returnvalue->showThat();}

  protected:

  private:

   RCIPtr value;

  };

  评估

  

  实现引用计数是需要有前提的,不是所有的情况下,使用引用计数都是合适的。适合情况如下:

  

  相对多的对象共享相对少量的实值。

  

  对象的实值产生或者销毁的成本很高,或者占用很多内存。

  

  但是要记住,即使是Java也会有内存泄漏,不要指望小小的引用计数(上面简单的实现)不会产生同样的问题。

  

  引用计数是一项很深奥的技术,想想Java,所以需要很谨慎的对待,但愿它能带来程序设计上的优化。

  

  

精彩图集

赞助商链接