C++中的智能指针

当设计含有指针的类时,应特别小心。因为指针指向的对象通常不包含在类的对象中,当类对象进行复制时,默认复制构造函数通常是浅拷贝(bitwise copy),只是拷贝了指针的值,这是两个指针指向同一个对象。通过其中一个指针就可以改变对象的值,也可以释放指针指向的对象;这时候另一个指针并不知情。引用C++ Primer的例子

class HasPtr{
public:
		HasPtr(int *p, int i):ptr(p),val(i){}
		//获取成员变量的接口
		int *get_ptr()const { return ptr;}
		int get_int const {return val;}
		//设置成员变量的接口
		void set_per(int *p){ptr=p;}
		void set_int(int i){val=i;}
		
		int get_ptr_val()const {return *ptr;}
		int set_ptr_val(int val)const {*prt=val;}//指针的值没变,所以可以为const		
private:
	int *ptr;
	int val;
}
按照如下使用:

int *ip=new int(42);
HasPtr prt1(ip,42);
HasPtr ptr2(ptr1);//bitwise copy
这时ptr1和ptr2中的指针指向同一个对象。假如有一个对象释放,运行析构函数(如果有的话),另一个对象中的指针将成为悬浮指针,而这个对象对此毫不知情。

为了避免类似的事情发生,C++中给我们提供了智能指针。智能指针的本质是使用一个类来管理指针。在这个类里面加了一个变量--引用计数,记录与指针对象关联的类的个数。只有当引用计数为零时,才可以释放指针指向的对象。智能指针的行为要和普通指针一样。但是智能指针多了引用计数,当引用指针类的个数发现变化时(比如复制构造函数和复制操作符),引用计数要体现出这样变换。例如,在复制构造函数中,引用计数应加1。而在赋值操作符(重载)中,左操作数使用的智能指针引用计数减1 ,而右操作数使用的智能指针引用计数加1。下一个问题就是要把这个引用计数放到哪里?可以放到类HasPtr中吗?如果放到HasPtr中

class HasPtr{

……

private:

int *ptr;int val;

size_t use;//引用计数

}

这样每个对象中就会有引用计数,当我们更新引用计数时,要更新每个对象中的use值,实在难以实现。

但是真的不能放到HasPtr中吗?只要确保每个对象都能知道引用计数的值,有能确保引用计数容易更新,就可以。方法是使用指针(指针型句柄就是这样做的)。

class HasPtr{
……		
private:
	int *ptr;
	int val;
	size_t *use;//引用计数
}


C++ Primer给我们的例子是使用计数类。

class U_Ptr{
	friend class HasPtr;
	int *ip;
	size_t use;
	U_Ptr(int *P):ip(p),use(1){}
	~U_Ptr(){ delete ip;}
}
HasPtr为友元。计数器类中的变量都为private。

使用智能指针类,要像使用普通指针一样,所以要重新设计HasPtr类

class HasPtr{
public:
		HasPtr(int *p, int i):ptr(new U_Ptr(p)),val(i){}
			
		//重新实现复制否造函数
		HasPtr(const HasPtr &orig):
			ptr(orig.ptr),val(orig.val){++ptr->use;}
		HasPtr&operator=(const HasPtr& rhs);
		//获取成员变量的接口
		int *get_ptr()const { return ptr->ip;}
		int get_int const {return val;}
		//设置成员变量的接口
		void set_per(int *p){ptr->ip=p;}
		void set_int(int i){val=i;}
		
		int get_ptr_val()const {return *ptr->ip;}
		int set_ptr_val(int val)const {*prt->ip=val;}//指针的值没变,所以可以为const		
		
private:
	U_Ptr *ptr;
	int val;
}
//实现赋值操作符重载
HasPtr& HasPtr::operator=(const HasPtr &rhs)
{
	++rhs.prt->use++;//右操作数智能指针的引用计数加1
	if(--ptr->use==0)//左操作数智能指针的引用计数减1
		delete ptr;
	ptr=rhs.ptr;
	val=rhs.val;
	return *this;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值