`

C++引用计数

 
阅读更多

主要参考《提高C++性能的编程技术》第12章 引用计数

 

设计思路

1. rc.h中:

(1) 提供RCObject,内部封装了refCount及其基本加减操作

(2) 提供RCPtr,是一个智能指针。普通的智能指针内部封装一个基本类型的指针,但这里的智能指针内部封装的是指向RCObject类型的指针。因此,这个智能指针可以根据RCObject维护的引用计数变量refCount来实现引用计数的优势,如:

       “赋值时复用”:在赋值操作时,只用refCount++即可复用已经在堆上创建好的原有实例;

       “自动释放”: 在引用计数refCount==0时,自动析构掉对象。

2. rc.cpp

    使用引用计数时候,要做两件事情。

(1) 继承RCObject,以便拥有refCount及其基本加减操作

class BigInt : public RCObject{

      ...

};

(2) 引用计数版本的BigInt——RCBigInt,内部封装BigInt的智能指针RCPtr<BigInt>,这样就可以“赋值时复用”和“自动释放”

class RCBigInt {
      ...
private:
      RCPtr<BigInt> value;
};

 

引用计数的优缺点

       结合代码,用脚趾头也能想明白上面设计的优缺点——

缺点:引用计数版本RCBigInt在创建时,由于又在内部套一个智能指针,又是创建refCount的,效率反而更慢;

优点:但是引用计数版本RCBigInt在赋值时,可以直接refCount++,就很快;并且refCount==0时,也不用手工去释放。

 

rc.h

#ifndef RC_H
#define RC_H

/*
  RCObject:引用计数类型的基类 
*/
class RCObject{
public:
       void addReference(){ ++refCount;}
       void removeReference(){
            if(--refCount == 0){
                delete this;
            }
       }
       void markUnshareable(){
            shareable = false;
       }
       bool isShareable() const{ return shareable; } /* 可否共享 */
       bool isShared() const {return refCount > 1; } /* 是否已经被共享 */ 
protected:
       RCObject():refCount(0), shareable(true){}
       RCObject(const RCObject& rhs):refCount(0), shareable(true){}
       RCObject& operator= (const RCObject& rhs){ return *this; } //?
       virtual ~RCObject(){}  //?virtual
private:
        int refCount;         /* 引用计数 */ 
        bool shareable;       /* 可否共享 */
};

/*
  RCPtr:封装了"引用计数类型RCObject的指针"的"智能指针"
  (1) 智能指针:
      本质上就是通过重载operator->和operator*操作符,在内部封装一个非智能指针的对象 
  (2) (支持引用计数的)智能指针: 
      内部封装的是一个 "指向RCObject类型的指针" 
      注:使用RCPtr<T>时保证,模板参数T是RCObject的子类 
*/
template<class T>
class RCPtr{
public:
       RCPtr(T *realPtr = 0): pointee(realPtr) { addRef(); }  //Ctor参数是 "指向RCObject类型的指针"
       RCPtr(const RCPtr& rhs): pointee(rhs.pointee) { addRef(); }  //Ctor参数是 "指向RCObject类型的指针"的"智能指针" 
       ~RCPtr(){
                if(pointee)
                    pointee->removeReference();
       }
       T* operator-> () const {return pointee;} /* member access: operator-> */
       T& operator* () const {return *pointee;} /* deference: operator* */
       RCPtr& operator= (const RCPtr& rhs); /* operator= */
private:
       T *pointee;  /* 指向RCObject类型的指针 */
       
       void addRef();  /* 尝试本引用计数++ */
};

template<class T>
void RCPtr<T>::addRef(){  
     if(0==pointee)
         return;
     if(false == pointee->isShareable()){//如果不能共享引用对象,则拷贝创建新的引用对象 
         pointee = new T(*pointee);
     }
     pointee->addReference();
}

template<class T>
RCPtr<T>& RCPtr<T>::operator= (const RCPtr& rhs){
    if(pointee != rhs.pointee){
        if(pointee)
            pointee->removeReference();
        pointee=rhs.pointee;
        addRef();
    }
}

#endif
         

 

rc.cpp

#include "rc.h"
#include <iostream>
#include <time.h>
using namespace std;

/*
  BigInt: 继承自RCObject,复用其引用计数的功能
  注意:继承了RCObject,只是拥有了引用计数的facility(计数变量refCount),但并不能带来任何好处;
        如果要用到引用计数的好处(赋值时避免复用以前堆中创建的),则必须同时用"智能指针"才行。 
*/
class BigInt : public RCObject{
      friend BigInt operator+ (const BigInt&, const BigInt&);
public:
      BigInt( const char *);
      BigInt( unsigned = 0);
      BigInt( const BigInt& );
      
      BigInt& operator= (const BigInt&);
      BigInt& operator+= (const BigInt&);
      ~BigInt();
      
      char *getDigits() const {
           return digits;
      }
      
      unsigned getNdigits() const{
           return ndigits;
      }
private:
      char *digits;       /* 低char存放低十进制位, 每位以unsigned int形式存入char(而非ASCII码) */
      unsigned ndigits;   /* 十进制位# */
      unsigned size;      /* 容量 */ 
      
      BigInt(const BigInt&, const BigInt&);            /* operational Ctor */ //???
      char fetch(unsigned i) const;
};

BigInt::BigInt(const char *s){
      if(s[0]=='\0'){
            s="0"; 
            //???对于0,统一成特殊情况'0'(ASCII码的'0')跟一个'\0'(即0) 
      }
      size = ndigits = strlen(s);
      digits = new char[size];
      for(unsigned i=0; i<ndigits; ++i){
          digits[i] = s[ndigits-1-i] - '0';
      }
}

BigInt::BigInt(unsigned u){
      unsigned v=u;
      for(ndigits=1;(v/=10)>0;++ndigits);
      
      digits = new char[size=ndigits];
      for(unsigned i=0;i<ndigits;++i){
            digits[i]=u%10;
            u/=10;
      }
}

BigInt::BigInt(const BigInt& copyFrom){
      size = ndigits = copyFrom.ndigits;
      digits = new char[size];
      
      for(unsigned i=0; i<ndigits; ++i){
            digits[i] = copyFrom.digits[i];
      }
}

BigInt& BigInt::operator= (const BigInt& rhs){
      if(this == &rhs)
            return *this;
            
      //如果size不够,则扩展char[] 
      ndigits = rhs.ndigits;
      if(ndigits > size){
            delete [] digits;
            digits = new char[size=ndigits];
      }
      
      for(unsigned i=0; i<ndigits; i++){
            digits[i] = rhs.digits[i];
      }
      
      return *this;
}

BigInt& BigInt::operator+= (const BigInt& rhs){
      //"必要时",size扩展到max 
      unsigned max = 1 + (rhs.ndigits > ndigits ? rhs.ndigits : ndigits);
      if( size < max ){
            char *d = new char[size=max];
            for( unsigned i = 0; i<ndigits; ++i){
                 d[i] = digits[i];
            }
            delete [] digits;
            digits = d;
      }
      
      //高位补0
      while( ndigits < max){
            digits[ ndigits++ ] = 0;
      } 
      
      for(unsigned i=0; i<ndigits; ++i){
            digits[i]+=rhs.fetch(i);
            if(digits[i]>=10){
                  digits[i]-=10;
                  digits[i+1]++;
            }
      }
      if(digits[ndigits-1]==0){//最高位没有进位时 
            --ndigits;
      }
      
      return *this; 
}

BigInt::~BigInt(){
      delete [] digits;
}

BigInt::BigInt(const BigInt& left, const BigInt& right){
      size = 1 + (left.ndigits > right.ndigits ? left.ndigits : right.ndigits);
      digits = new char[size];
      ndigits = left.ndigits;
      
      for(unsigned i=0; i<ndigits; i++){
            digits[i] = left.digits[i];
      }
      
      *this += right;
}

inline char BigInt::fetch(unsigned i) const{
      return i<ndigits ? digits[i] : 0 ;
}


/*
  引用计数版本的BigInt——RCBigInt,内部封装智能指针RCPtr<BigInt>,这样就可以“赋值时复用”和“自动释放”
*/
class RCBigInt {
      friend RCBigInt operator+ (const RCBigInt&, const RCBigInt&);
public:
      /*RCBigInt*/
      RCBigInt (const char *p): value(new BigInt(p)){}
      RCBigInt (unsigned u=0): value(new BigInt(u)){}
      RCBigInt (const BigInt& bi): value(new BigInt(bi)){}
private:
      RCPtr<BigInt> value;
};

inline
RCBigInt operator+ (const RCBigInt& left, const RCBigInt& right){
      return RCBigInt( *(left.value) + *(right.value) );
}

/*test assignment*/
void testBigIntAssign(int n){
     //单纯继承了RCObject的BigInt只是拥有了refCount,但并不能够在赋值时复用曾经在堆中的对象,它和普通的类型效果一样 
     BigInt a, b, c;
     BigInt d = 1;
     
     time_t start = time(0);
     for(int i=0;i<n;++i){
         a = b = c = d; //慢,∵每次在堆中创建新的 
     }
     time_t end = time(0);
     
     printf("%d\n", end-start);
}

void testRCBigIntAssign(int n){
     //只有使用了"基于引用计数的智能指针RCPtr"以后,BigInt才能在赋值时复用曾经在堆中的对象 
     RCBigInt a, b, c;
     RCBigInt d = 1;
     
     time_t start = time(0);
     for(int i=0;i<n;++i){
         a = b = c = d; //快,∵复用已经创建好的 
     }
     time_t end = time(0);
     
     printf("%d\n", end-start);
}

/*test creation*/
void testBigIntCreate(int n){
          
     time_t start = time(0);
     for(int i=0;i<n;++i){
         BigInt a = i;
         BigInt b = i+1;
         BigInt c = i+2;
         BigInt d = i+3;  
     }
     time_t end = time(0);
     
     printf("%d\n", end-start);
}

void testRCBigIntCreate(int n){ 
          
     time_t start = time(0);
     for(int i=0;i<n;++i){
         RCBigInt a = i;
         RCBigInt b = i+1;
         RCBigInt c = i+2;
         RCBigInt d = i+3;  
     }
     time_t end = time(0);
     
     printf("%d\n", end-start);
}

int main(){
    testRCBigIntCreate(5000000);
    testBigIntCreate(5000000);
    
    testRCBigIntAssign(500000000);
    testBigIntAssign(500000000);
    
    system("pause");
    return 0;
}

 

 

 

 

 

分享到:
评论

相关推荐

    C++引用计数设计与分析(解决垃圾回收问题).docx

    引用计数是C++中解决动态内存管理的一种策略,特别是在需要避免内存泄漏的情况下。引用计数的基本思想是跟踪和记录对象被引用的次数。每当一个对象被创建或复制时,其引用计数增加1。当对象被销毁或复制到其他地方时...

    引用计数的c++源码实现

    引用计数是一种常见的内存管理策略,特别是在C++中,它被用于智能指针类,如`std::shared_ptr`和`std::weak_ptr`。在本项目中,我们看到一个用C++实现的引用计数系统,这个系统可能是为了自定义的智能指针或者对象...

    C++ 引用计数技术及智能指针的简单实现

    总结起来,智能指针通过引用计数技术为C++程序员提供了自动内存管理的便利,减少了手动内存管理带来的风险和复杂性,提高了代码的可靠性和安全性。理解并正确使用智能指针是C++开发中的重要技能。

    COM学习——动态绑定之引用计数

    C++中实现COM对象的引用计数通常通过IUnknown接口来完成,IUnknown是所有COM接口的基础,提供了三个基本方法:QueryInterface、AddRef和Release。QueryInterface用于获取对象支持的其他接口;AddRef增加引用计数,...

    COM-引用计数

    当引用计数降为0时,表示没有客户端在使用该对象,此时对象可以被安全地销毁,其占用的内存得以回收。 在VC6.0这样的开发环境中,开发者可以直接使用COM API来创建、使用和释放COM对象。例如,通过`...

    智能指针与引用计数详解

    智能指针是C++编程中一个非常...总之,智能指针与引用计数是C++中管理动态内存的重要工具,通过理解和掌握这些知识,程序员可以编写出更加安全、高效的代码。通过分析和实践这个demo,将有助于深化对这一主题的理解。

    C++实现 带引用计数的智能指针

    本文将详细讨论如何在C++中实现一种带引用计数的智能指针。 引用计数是一种常见的智能指针策略,它维护了一个内部计数,记录有多少个智能指针指向同一个对象。当智能指针被创建或复制时,计数增加;当智能指针被...

    C++ 对象计数.rar_counting object_计数

    在C++中,`std::shared_ptr` 是一种支持引用计数的智能指针,它是C++11标准库的一部分。 ### 2. std::shared_ptr `std::shared_ptr` 用于管理动态分配的对象,它维护了一个内部的引用计数。每当创建一个新的 `std:...

    C++智能指针(含内存计数)

    每个`std::shared_ptr`都会增加其所指向对象的引用计数,当一个`std::shared_ptr`被销毁或赋值给其他`std::shared_ptr`时,相应的引用计数会减少。当引用计数降为零时,智能指针将自动调用析构函数释放对象的内存。...

    MyString 字符串类仿写_C++_(四种版本,引用计数,迭代器,加锁)

    这里我们将探讨一个名为"MyString"的自定义字符串类的四个不同版本,每个版本都增加了特定的功能,如引用计数、写时拷贝、加锁以及迭代器支持。 首先,`MyString(v1.0)`可能是实现基础功能的版本,包含基本的字符串...

    引用(C++里的藿香正气)的真相-(VC编译器如何实现引用规则)

    6. **内存管理**:由于引用并不持有对象,因此不涉及引用计数或析构问题。对象的生命周期由原始变量控制,引用只是提供了一个额外的访问途径。 总结来说,C++的引用在VC编译器的实现中,主要是通过编译器的优化和...

    C++多项式运算类

    它利用了C++的数据结构概念以及一种内存管理技巧——引用计数。 首先,我们需要理解数据结构是如何在这个上下文中起作用的。在C++中,数据结构是组织和存储数据的方式,使得数据可以更高效地被访问和处理。在这个...

    smartptr——基于自动引用计数的智能指针

    智能指针相信大家听说过吧,我理解的智能指针,既是一个C++模板类,重载了指针操作符...内部实现的关键在于:自动地址引用计数、操作符重载。 可以实现任意类型(基本数据类型、自定义类型)的指针地址的自动引用计数。

    C++智能指针实现(包含拷贝构造,赋值函数,引用解引用重载)

    智能指针实际上是一个封装了原始指针的对象,它拥有一个内部的引用计数,用于跟踪有多少个智能指针指向同一块内存。当智能指针被销毁或赋值给其他智能指针时,这个引用计数会被相应地增加或减少。当引用计数变为零时...

    C++实现自动内存回收

    在这个话题中,我们将深入探讨C++中的智能指针、内存池、引用计数等技术,这些都是实现垃圾回收机制的关键概念。 首先,智能指针是C++中用来模拟自动内存管理的一种手段。C++11引入了std::unique_ptr、std::shared_...

    基于C++内联汇编原子操作引用计数的CXX智能指针设计与实现+全部资料齐全+部署文档.zip

    基于C++内联汇编原子操作引用计数的CXX智能指针设计与实现+全部资料齐全+部署文档.zip 【备注】 1、该项目是个人高分项目源码,已获导师指导认可通过,答辩评审分达到95分 2、该资源内项目代码都经过测试运行成功,...

    C++智能指针实现

    对一个对象进行赋值时,赋值操作符减少左操作数所指对象的引用计数(如果引用计数为减至0,则删除对象),并增加右操作数所指对象的引用计数;调用析构函数时,构造函数减少引用计数(如果引用计数减至0,则删除基础...

    c++智能指针的实现

    对一个对象进行赋值时,赋值操作符减少左操作数所指对象的引用计数(如果引用计数减至0,则删除对象),并增加右操作数所指对象的引用计数; 调用析构函数时,减少引用计数(如果引用计数减至0,则删除基础对象); ...

    混用智能指针和引用计数类型的指针示例

    首先,`std::shared_ptr`是C++11引入的一种智能指针,它采用引用计数来跟踪多个`shared_ptr`对象对同一对象的所有权。当最后一个拥有该对象的`shared_ptr`被销毁时,对象也会被删除。这使得智能指针具有了自动释放...

Global site tag (gtag.js) - Google Analytics