C++中,标准库的使用大大减少了现代C++程序中对指针的需要。然而,许多应用程序仍然需要使用指针,特别是在类的实现中,并且包含指针的类复制控制方面容易出错。
具有指针成员的对象一般需要定义复制控制成员。如果依赖合成版本,会给类的用户增加负担。用户必须保证成员所指向的对象存在,只要还有指针指向该对象。为了管理这些具有指针成员的类,必须定义三个复制控制成员:复制构造函数、赋值操作符和析构函数。这些成员可以定义指针成员的指针型行为或值型行为,或者智能指针类(需要一个使用计数类配合)。
大多数C++类采用三种方法管理指针成员。
(1)指针成员采取常规指针型行为。复制指针时只复制指针中的地址,而不会复制指针指向的对象。这样的类具有指针的所有缺陷但无需特殊的复制控制。
常规指针类:
class HasPtr{ public: HasPtr(int *p):ptr(p){} HasPtr(const HasPtr& Hp):ptr(Hp.ptr){} int get_ptr()const{retrun ptr;} void set_ptr(int *p){ptr=p;} int get_ptr_val()const {return *ptr;} private: int *ptr; } 如(出现悬垂指针!!!) int *p=new int(10); HasPtr ptr(p);//HasPtr points to same object as p does delete p;//object pointed to by p is freed ptr.set_ptr_val(0);//disaster: The object to which HasPtr points was freed!
(2)类可以实现所谓的“智能指针”(smart pointer)行为。指针所指的对象仍是共享的,但类能够防止悬垂指针(指向了不存在的对象的指针)。
解决办法:为指向同一共享对象的指针引入了一个使用计数use count:记录指向共享对象的类对象数目。初始:新创建一个类对象,使用计数初值为1。
即智能指针将一个计数器与类指向对象想关联起来。
使用计数类(有两种经典策略实现,另一种见:句柄类区别在于:类指针成员所指对象由谁直接关联(智能指针类:由使用计数类直接关联;句柄类:由句柄类自己直接关联。)):这里:定义一个单独的具体类:封装使用计数和相关指针。
class HasPtr;//智能指针类声明 class U_Ptr{ //定义为私有(class默认:private) friend class HasPtr;//友元 int *ip; size_t use; U_Ptr(int *p):ip(p),use(1){} ~U_Ptr(){delete ip;} }
智能指针类:
class HasPtr{public: HasPtr(int *p):ptr(new U_Ptr(p)){} HasPtr(const HasPtr& Hp):ptr(Hp.ptr){++ptr->use} int get_ptr()const{retrun ptr;} void set_ptr(int *p){ptr=p;} int get_ptr_val()const {return *ptr;} HasPtr& operator=(const HasPtr&rhs) { ++rhs.ptr->use;//可防止自身复制 if(--ptr->use==0)delete ptr; ptr=rhs.ptr; return *this; } ~HasPtr(){if(ptr->use==0)delete ptr;} private: U_Ptr *ptr; };
(3)类采取值型行为。将指针成员所指基础值的副本给每个对象。每个指针所指向的对象是唯一的,由每个类对象独立管理。
使指针成员表现的想一个值(指针的值型行为),复制值型对象时,会得到一个不用的新副本。即复制指针所指向的对象,而不是复制指针本身。
值型类:
class HasPtr{ public: HasPtr(const int *p):ptr(new int(*p)){} HasPtr(const HasPtr& orig):ptr(new int (*orig.ptr)){} HasPtr& operator=(const HasPt&rhs) { *ptr=*rhs.ptr; return 0; } int get_ptr_val()const{return *ptr;} int* get_ptr()const{return ptr;} void set_ptr(int *p){ptr=p;} ~HasPtr(){delete ptr;} private: int *ptr; };