智能指针(smart point)
除了增加功能外,其行为像普通指针一样。 一般通过使用计数(use count)或引用计数(reference count)实现智能指针,防止出现指针垂悬。
下面是一个普通带指针的类代码:
#ifndef HASPTR_H
#define HASPTR_H 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_ptr(int *p){ptr = p;}
void set_int(int i){val = i;} int get_ptr_val()const{return *ptr;}
void set_ptr_val(int val)const{ *ptr = val;}
private:
int *ptr; //common pointer
int val;
}; #endif // HASPTR_H
小心地雷:
具有指针成员且使用默认合成构造函数的类具有普通指针的所有缺陷。尤其是,类本身无法避免垂悬指针。
一般有两种策略使用引用计数:
1、单独定义一个具体类用以封装使用计数和相关指针:(一般将该类设为私有类,仅友元类可以访问)
//private class for use by HasPtr only
class U_ptr{
friend class HasPtr;
int *ip;
size_t use;
U_ptr(int* p):ip(p),use(1){}
~U_ptr(){delete ip;}
}; HasPtr& HasPtr::operator =(const HasPtr& rhs){
++rhs.ptr->use;//increment use count on rhs first
if(--ptr->use == 0) //if use count goes to 0 on this object, delete it
delete ptr;
ptr = rhs.ptr;//copy the U_ptr
val = rhs.val;//copy the int member
return *this;
}
下面是原来的HasPtr类
class HasPtr{
public:
//HasPtr owns the pointer, p must been dynamically allocalted
HasPtr(int *p, int i):ptr(new U_ptr(p)),val(i){}
//copy memebers and increment the use count
HasPtr(const HasPtr& orig):
ptr(orig.ptr),val(orig.val){ ++ptr->use;}
HasPtr& operator=(const HasPtr&);
//if use count goes zero, delete th U_ptr object
~HasPtr(){
if (--ptr->use == 0)
delete ptr;
} int *get_ptr()const{return ptr->ip;}
int get_int()const{return val;} void set_ptr(int *p){ptr->ip = p;}
void set_int(int i){val = i;} int get_ptr_val()const{return *ptr->ip;}
void set_ptr_val(int val){*ptr->ip = i;}
private:
U_ptr* ptr;
int val;
};
复制操作比复制构造函数要复杂点,一般现将右操作数引用计数加1, 然后左操作数对象引用计数减1并检查这个引用计数。
HasPtr& HasPtr::operator =(const HasPtr& rhs){
++rhs.ptr->use;//increment use count on rhs first
if(--ptr->use == 0) //if use count goes to 0 on this object, delete it
delete ptr;
ptr = rhs.ptr;//copy the U_ptr
val = rhs.val;//copy the int member
return *this;
}
注解: 这个赋值操作符在减少左操作数的使用计数之前使rhs的使用计数加1,从而防止自身赋值。
现在需要改变访问int*的其他成员,以便通过U_ptr指针简洁获取int
定义值类型:
处理指针成员的另一种完全不同的方法,是给指针成员提供值语义(value semantics), 复制值对象时,会得到一个不同的新副本。对副本的操作不会反映到原有对象上,反之亦然。
代码示例如下:
#ifndef VALUE_PTR_H
#define VALUE_PTR_H class HasPtr{
public:
HasPtr(const int&p, int i):ptr(new int(p)),val(i){}
HasPtr(const HasPtr& orig):ptr(new int(*orig.ptr)),val(orig.val){}
HasPtr& operator=(const HasPtr&);
~HasPtr(){delete ptr;} int get_ptr_val()const{return *ptr;}
int get_int()const{return val;} void set_ptr(int* p){ptr = p;}
void set_int(int i){val = i;} int* get_ptr()const{return ptr;}
void set_ptr_val(int val){*ptr = val;}
private:
int* ptr;
int val;
}; HasPtr& HasPtr::operator =(const HasPtr& rhs){
*ptr = *rhs.ptr; //copy the value pointer to
val = rhs.val; //copy the int
return *this;
}
#endif // !VALUE_PTR_H
注解: 即使要讲一个对象赋值给它本身,赋值操作符也必须总是保证正确。 本例中,即使左右操作数相同,操作本质上也是安全的,因此,不需要显示检查自身赋值。