读C++ Primer 之 句柄类

我们知道C++中最令人头疼的当属指针,如果您申请了对象却没有释放它,时间一长就会造成系统崩溃,大量的内存溢出使得您的程序的健壮性出现问题

而句柄类就是为了能够解决这一问题而出现的,句柄类有点类似于智能指针。

好了,废话不多说,我们来看代码


首先我们来看 sample.h文件的代码:

/*
* author:xizero00
* mail:xizero00@163.com
* date:2011-08-07 20:11:24 
* Handle Class Sample  句柄类示例
*/

#ifndef SAMPLE_H
#define SAMPLE_H

#include <iostream>
#include <stdexcept>
using namespace std;




//基类
class Item_base
{
public:
	//基类的虚函数,用于智能地复制对象
	virtual Item_base* clone() const
	{
		return new Item_base( *this );
	}
};


//子类
class Bulk_item: public Item_base
{
	//子类的虚函数的重载,用于智能地复制对象
	virtual Bulk_item* clone() const
	{
		return new Bulk_item( *this );
	}
};

//子类的子类
class Sales_item: public Bulk_item
{
public:
	//默认构造函数,用来初始化一个引用计数器
	Sales_item(): p( 0 ) , use( new size_t( 1 ) ) { cout << "Sales_item的引用计数器初始化为1" << endl; }
	
	//带有一个参数的,且该参数为基类引用的构造函数
	Sales_item( const Item_base& );
	
	
	
	//复制构造函数,需要注意的是,每复制一次就需要增加引用计数一次
	Sales_item( const Sales_item &i ): p( i.p ) , use( i.use ) { ++*use; cout << "由于采用了复制构造函数,Sales_item类型的对象引用计数为:" << *use << endl;} //也可以这样写
	//Sales_item( const Sales_item &i ): p( i.clone() ) , use( new size_t( 1 ) ) { ++*use; }
	
	
	//析构函数,析构的时候会判断是否能够释放指针所指向的数据
	~Sales_item() { cout << "在析构函数中:"; decr_use(); }
	
	
	//赋值操作符重载
	Sales_item& operator= ( const Sales_item& );
	
	//访问操作符重载
	const Item_base* operator-> () const
	{
		if( p )
		{
			return p;
		}
		else
		{
			throw logic_error( "p指针错误" );
		}
	}
	
	//解引用操作符重载
	const Item_base& operator* () const
	{
		if( p )
		{
			return *p;
		}
		else
		{//重载虚函数,用于智能地复制对象
			throw logic_error( "p指针错误" );
		}
	}
	
	
	//重载虚函数,用于智能地复制对象
	/*
	virtual Sales_item* clone() const
	{
		return new Sales_item( *this );
	}
	*/
	
private:
	//两个指针存储着引用计数器以及数据的指针
	Item_base *p;
	size_t *use;
	
	//减少引用
	void decr_use()
	{
		cout << "在 dec_use函数中引用计数减少了,当前计数值为:" << *use - 1 << endl;
		if( --*use == 0 )
		{
			delete p;
			delete use;
			cout << "在 dec_use函数中计数器减为0,释放对象" << endl;
		}
		
	}
};


//赋值操作符重载,每次复制都会增加引用计数
Sales_item& Sales_item::operator= ( const Sales_item &si )
{
	cout << "由于采用类赋值操作,";
	cout << "被赋值的对象的引用计数为:" << *si.use ;
	cout << "即将被赋值的对象的引用计数为:" << *use << endl;
	//这里需要特别注意的就是待复制的对象的计数器需要加1而被赋值的对象需要减1	
	
	//增加被复制对象的引用计数
	++*si.use;
	cout << "被赋值的对象的赋值之后的引用计数为:" << *si.use << endl;
	//将即将被赋值的对象的引用计数减1
	decr_use();
	cout << " 即将被赋值的对象赋值之后的引用计数为:" << *use << endl;
	
	
	//复制指针
	p = si.p;
	use = si.use;
	
	//返回
	return *this;
}


#endif //SAMPLE_H

接下来我们来看sample.cc的代码:

/*
* author:xizero00
* mail:xizero00@163.com
* date:2011-08-07 20:11:24 
*/
#include "sample.h"
int main( int argc , char **argv )
{
	//重点关注i1和i2的引用计数
	Sales_item i1 , i2;//i1和i2的引用计数分别为1
	Sales_item i3( i1 );//i1的引用计数变为2
	Sales_item i4 = i1;//i1的引用计数变为3,因为这样还是调用的复制构造函数
	i4 = i2; // i2的引用计数变为2
	
	return 0;
}

下面给出编译所需的Makefile

# author:xizero00
# mail:xizero00@163.com
# date:2011-08-08 00:51:25 
install:
	g++ sample.cc -g -o sample
	ls -al sample*
	./sample
clean:
	rm -f sample
	ls -al sample*

注意:代码是在linux下编译,您只需要将三个文件放在同一个目录,然后在当前目录打开终端,输入make,就可以查看到结果。

如果您想清理生成的文件 输入make clean即可

下面是我执行的结果:

Sales_item的引用计数器初始化为1
Sales_item的引用计数器初始化为1
由于采用了复制构造函数,Sales_item类型的对象引用计数为:2
由于采用了复制构造函数,Sales_item类型的对象引用计数为:3
由于采用类赋值操作,被赋值的对象的引用计数为:1即将被赋值的对象的引用计数为:3
被赋值的对象的赋值之后的引用计数为:2
在 dec_use函数中引用计数减少了,当前计数值为:2
 即将被赋值的对象赋值之后的引用计数为:2
在析构函数中:在 dec_use函数中引用计数减少了,当前计数值为:1
在析构函数中:在 dec_use函数中引用计数减少了,当前计数值为:1
在析构函数中:在 dec_use函数中引用计数减少了,当前计数值为:0
在 dec_use函数中计数器减为0,释放对象
在析构函数中:在 dec_use函数中引用计数减少了,当前计数值为:0
在 dec_use函数中计数器减为0,释放对象

结论:我们可以看到,句柄类能够很方便并且能够很安全地释放内存,不会导致内存的泄露。


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值