c++引用计数

为什么要用引用计数? 

       场景:代码里X是一个非常重要的资源,模块A,B,C都有对其指针的引用,那么为了不出现内存泄露,常规的代码我们要怎么写?

               1. A 模块用完X时,需要检查B,C是否还在引用X,如果B,C有一个在用,那么X只要删除掉对A的引用就可以了,

                  如果B,C对A都已经没有引用了,那么A需要删除对X的引用时,要同时清除掉X。

               2.同样B,C在用完X时,也要重复做1里面的事情。

                 这样,代码将会多了许多的逻辑判断,同时模块B,C还需要对模块A提供查询是否在引用X的接口。

        可以不这么恶心吗?

        思考:能否A在释放X前,不需要知道是谁在引用X,只要知道有多少人在引用X?

        回答:是的,如果只有我用X,那么我就直接删除,如果还有其他人用,我就什么都不管,只要去除掉对X的引用就可以了。  情况就会变的好一些。

        那么如何做到能知道资源的引用次数那?

        这就需要对每一个资源X的都有一个的计数,这个计数是和资源X的生命周期息息相关的。

        那么如何来管理这个计数?怎么能在有模块引用资源X的时候,计数++,模块释放资源X的时候计数--那?

        这个就有一定难度了,引用的方式会有很多种,比如  A = X;   A.push_back(X);  A[100] = X; ...

        当然我们可以在代码里的每一处增加和释放资源引用的地方,都加上代码count++,count--;但这亦然很麻烦,维护成本很高。

        如何简单些?

        能否把对资源的引用和释放,看成是对一个类的拷贝和销毁来完成? 弄一个代理类,里面封装好计数和资源X。

        把所有对资源X的引用都理解成对代理类的引用,对代理类的引用都理解成对代理类的拷贝,对代理的释放就是销毁代理类。

        这样我们只需要在代理类的拷贝函数里count++ , 代理类的析构做count--就好了。

        如果代理类的资源引用计数count 减为0,就看成所有人都释放了对资源X的引用,这时由代理类来完成对资源的销毁。

#ifndef Ref_hpp
#define Ref_hpp

#include <iostream>
#include <string>

template <typename T>
class RefPtr;

template <typename T>
class Ref {
private:
    Ref(T *ptr);
    ~Ref();
    
    friend class RefPtr<T>; //定义指针管理类为友元,因为管理类需要直接操作指针类

    /**
     *  增加引用计数
     */
    void ref();
    
    /**
     *  减少引用计数
     *
     *  @param count <#count description#>
     */
    void unref();
    
    /**
     *  返回引用计数的个数
     *
     *  @return <#return value description#>
     */
    int getCount();
    
private:
    int count; //引用计数
    T *p; //基础对象指针
};

template <typename T>
Ref<T>::Ref(T *ptr) : p(ptr), count(1) {
     
}

template <typename T>
Ref<T>::~Ref() {
//    count--;
//    if (count <= 0) {
//        count = 0;
//        delete p;
//    }
    delete p;
}

template <typename T>
void Ref<T>::ref() {
    count++;
}

template <typename T>
void Ref<T>::unref() {
    count--;
    if (count < 0) {
        count = 0;
    }
}

template <typename T>
int Ref<T>::getCount() {
    return count;
}


template <typename T>
class RefPtr {
public:
    RefPtr(T *ptr);
    RefPtr(const RefPtr<T>&);
    ~RefPtr();
    
    RefPtr& operator=(const RefPtr<T>&);
    T & operator*();
    T * operator->();
    
    inline std::string getTag() { return _tag; };
    void setTag(const std::string value) { _tag = value; };
    
    inline int getRefCount() { return ref->getCount(); }
    
private:
    Ref<T> *ref;
    std::string _tag;
};


/**
 *  构造函数
 */
template <typename T>
RefPtr<T>::RefPtr(T *ptr) : ref(new Ref<T>(ptr)), _tag("") {
    
}

/**
 *  构造函数,不需要对参数进行计数操作
 */
template <typename T>
RefPtr<T>::RefPtr(const RefPtr<T> & nref) {
    ref = nref.ref;
    ref->ref();
    _tag = "";
}

/**
 *  销毁函数
 */
template <typename T>
RefPtr<T>::~RefPtr() {
    ref->unref();
    if (ref->getCount() <= 0) {
        delete ref;
    }
    std::cout << this->getTag() << " leave " << ref->getCount() << "次" << std::endl;
}

/**
 *  重载操作符=
 *  左值引用计数减一,右值引用计数加一
 *
 *  @param rhs <#rhs description#>
 *
 *  @return <#return value description#>
 */
template <typename T>
RefPtr<T> & RefPtr<T>::operator=(const RefPtr<T>& rhs) {
    rhs->ref->ref();
    ref->unref();
    
    if (ref->getCount() <= 0) {
        delete ref;
    }
    
    ref = rhs->ref;
    
    return *this;
}

/**
 *  重载操作符*
 *
 *  @return <#return value description#>
 */
template <typename T>
T & RefPtr<T>::operator*() {
    return *(ref->p);
}

/**
 *  重载->操作符
 *
 *  @return <#return value description#>
 */
template <typename T>
T * RefPtr<T>::operator->() {
    return ref->p;
}


#endif /* Ref_hpp */

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值