zoukankan      html  css  js  c++  java
  • C++ 引用计数

    原址:  https://blog.csdn.net/u012501459/article/details/48229399

    C++没有像java那样的垃圾回收机制,但是我们可以实现一个。一种很简单的方式就是使用引用计数。它实际上是一种用对象来管理资源的方式,因为普通的栈上的对象在离开作用域时会调用对应的析构函数,根据这个特性,可以实现用于对指针进行管理的类。

    下面以一个对int*指针的管理来说明引用计数是如何实现的。

    当我们创建一个int型指针时:int *p=new int(10);

    在最后我们需要调用delete p;

    通过接下来指定的方式,我们可以不用显示调用delete p;这行代码而又能够释放掉通过new关键字分配的内存,就是通过引用来实现的。

    先列出下面一张图表:

    上面是我们需要使用的int*指针以及需要定义的两个类Referenced和Ref_ptr类,其实Referenced类对用户而言是不可见的,就是用户在使用引用计数的过程中都不会用到这个类,这个类只在Ref_ptr内部被调用。

    执行Ref_ptr r1=new int(4);//调用构造函数

    Ref_ptr r2=r1;//调用拷贝构造函数

    时的过程如下图:

     下面是这两个类的类图:

    #include <iostream>
    #include <string>
     
    using namespace std;
     
    class Referenced 
    {
    public:
    	//初始化这个类,引用计数设为1,并且将p指向传入的地址
    	Referenced(int * pi)
    	{
    		refCount=1;
    		p=pi;
    	}
     
    	//引用计数加1
    	int ref()
    	{
    		return ++refCount;
    	}	
     
    	//引用计数减1
    	int unref()
    	{
    		return --refCount;
    	}
     
    	//返回引用计数
    	int count()
    	{
    		return refCount;
    	}
     
    	//析构函数,释放掉内存
    	~Referenced()
    	{
    		cout<<"delete referenced"<<endl;
    		delete p;
    	}
    private:
    	int refCount;//引用计数,表示有多少个变量引用这块内存
    	int * p;//真实的指针
    };
     
    //对指针进行管理的类,持有一个Referenced类的指针ptr,根据ptr中的
    //引用计数来判断是否调用delete来删除掉这个指针ptr
    class  Ref_ptr
    {
    public:
     
    	//使用int*指针初始化ptr,注意必须要放在初始化列表中
    	Ref_ptr(int * i):ptr(new Referenced(i))
    	{
    	}
     
    	//拷贝构造函数,又有一个变量指向了这块内存
    	Ref_ptr(const Ref_ptr & rhs)
    	{
    		ptr=rhs.ptr;//将右操作数的引用计数对象赋值给左操作数
    		ptr->ref();//将它们的应用计数加1
    	}
     
    	//赋值操作符,右操作数的引用计数要减1,左操作数的引用计数要加1
    	Ref_ptr & operator=(const Ref_ptr & rhs)
    	{
    		if(&rhs==this)
    			return *this;
    		if(ptr->unref()==0)//赋值操作符,首先将当前类的引用计数减1
    		{
    			cout<<"delete Ref_ptr"<<endl;
    			delete ptr;
    		}
    		ptr=rhs.ptr;//将右操作数的引用计数赋值给当前对象
    		ptr->ref();//引用计数加1
    		return *this;
    	}
     
    	//析构函数,引用计数要减1,如果减为0,删除这块内存
    	~Ref_ptr()
    	{
    		if(ptr->unref()==0)
    		{
    			cout<<"delete Ref_ptr"<<endl;
    			delete ptr;
    		}
    	}
    private:
    	Referenced * ptr;
    };
     
    int main()
    {
    	//Referenced rd=new int(4);
    	Ref_ptr r=new int(4);
    	Ref_ptr r1=new int(5);
    	r=r1;
     
    	getchar();
    	return 0;
    }
    

      

    _________________________________________________________________________________________________________________________________________________
    每一个不曾起舞的日子,都是对生命的辜负。
    But it is the same with man as with the tree. The more he seeks to rise into the height and light, the more vigorously do his roots struggle earthward, downward, into the dark, the deep - into evil.
    其实人跟树是一样的,越是向往高处的阳光,它的根就越要伸向黑暗的地底。----尼采
  • 相关阅读:
    设计模式之八:外观模式(Facade)
    Python模块学习笔记— —time与datatime
    Android加载图片OOM错误解决方式
    [C#]Attribute特性(2)——方法的特性及特性参数
    [C#]Attribute特性
    [Winform]一个简单的账户管理工具
    [C#]AES加密算法实现
    [C#基础]ref和out的区别
    [Socket网络编程]一个封锁操作被对 WSACancelBlockingCall 的调用中断。
    [Socket网络编程]由于套接字没有连接并且(当使用一个 sendto 调用发送数据报套接字时)没有提供地址,发送或接收数据的请求没有被接受。
  • 原文地址:https://www.cnblogs.com/leoking01/p/14591265.html
Copyright © 2011-2022 走看看