C++一些注意点之指针成员管理

来源:互联网 发布:经济数据分析论文 编辑:程序博客网 时间:2024/06/01 20:26

      C++类中经常含有指针,但是如何处理这个问题,本文针对<<C++ Primer>>和<<C++沉思录>>的方法进行了一点小结。本文只是浅尝辄止,深了自己都不懂了,且本文的例子漏洞百出,本文旨在总结这几种处理方法。

 

类中含有指针带来的一些问题

     设计具有指针成员的类时,类设计者必须首先需要决定的是该指针应提供什么行为。将一个指针复制到另一个指针时,两个指针指向同一个对象。当两个指针指向同一对象时,可以使用任一指针改变对象。类似地,很可能一个指针了一个对象时,另一个指针的用户还没有发现。

      通过不同的复制控制策略,可以为指针成员实现不同的行为。通常有以下五种策略(个人之见):

    (1)指针成员采取常规指针行为。这样的类具有所有指针缺限,但是不需要用户编写复制控制程序;

    (2)类采取值行为。复制的时候,另外分配空间,但是值与被复制对象一致;

    (3)采取拥有权转移。即被复制对象释放指针的引用。标准库的auto_ptr;

    (4)实现所谓的“智能指针”。共享对象,但是能防止“悬垂指针”;

    (5)“写时复制”技术。在修改的时候才去重新分配空间。

 

策略一:常规指针行为

      这种方式的赋值操作符/复制构造函数采用系统默认的,两个复制的对象共用相同的空间,这会带来一些析构时遇到的问题。

#include<iostream>using namespace std; class HasPtr{public:     HasPtr(int *p):ptr(p){}     int* getPtr()const     {return ptr;}     void setPtr(int *p)     {ptr = p;}     int& operator*()//返回引用可以对其赋值     {return *ptr;}     const int& operator*()const     {return *ptr;}     int* operator->()     {return ptr;}     const int* operator->()const     {return ptr;}     ~ HasPtr(){delete ptr;}private:     int *ptr;}; int main(){    HasPtr p1(new int(5));    HasPtr p2(p1);    *p1 = 12;    cout<<*p1<<endl;//12    cout<<*(p2.operator->())<<endl;//12    system("pause");    return 0;}



策略二:“值复制”行为

       这种方式在复制的时候,采用“值复制”的方式。即复制的时候不复制空间指针,而是重新分配空间,但是其“值”与被复制的对象“值”一样。一般笔试时,string可以采用这种类型。

/*copyright@ CNV && lsj*/ #include<iostream>using namespace std; class HasPtr{public:    HasPtr(int *p):ptr(p){}    HasPtr(const HasPtr& other):ptr(new int(*other))    {}    HasPtr& operator=(const HasPtr& other)    {      if(&other != this)           *ptr = *other;//如果是数组的话这里,要释放掉原来的值       return *this;    }    int& operator*()//返回引用可以对其赋值    {return *ptr;}    const int& operator*()const    {return *ptr;}    int* operator->()    {return ptr;}    const int* operator->()const    {return ptr;}    ~ HasPtr(){delete ptr;}private:    int *ptr;}; int main(){    HasPtr p1(new int(5));    HasPtr p2(p1);    *p2 = 13;    cout<<*p1<<endl;//5    cout<<*p2<<endl;//13    system("pause");    return 0;}



策略三:拥有权转移行为

      被复制的对象释放对指针的拥有权,由左边对象接管指针的拥有权。标准库auto_ptr采用了这种策略。

/*copyright@ CNV && lsj*/ #include<iostream>using namespace std; class HasPtr{public:   HasPtr(int *p):ptr(p){}   HasPtr(const HasPtr& other)   {      ptr = other.getPtr();      other.setPtr(NULL);   }    HasPtr& operator=(const HasPtr&other)   {      if(&other!=this){          ptr = other.getPtr();          other.setPtr(NULL);       }       return *this;   }   int getPtr()const   {return ptr;}    void setPtr(int *p)   {ptr = p;}   ~ HasPtr()   {       if(ptr)delete ptr;   }private:    int *ptr;};



策略四:智能指针行为

     这种策略虽然还是采用多个对象共享同一份地址空间,但是通过给类添加计数器,能够有效的防止“悬垂指针”。实现智能指针有两种方案(C++ Primer):计数伙伴类和句柄类。

方案1:设计伙伴计数类。

/*copyright@ CNV && lsj*/ #include<iostream>using namespace std; class HasPtr;class Uptr{//计数伙伴类    friend class HasPtr;    int *ip;//本来应该包含这个指针    size_t use;    Uptr(int *p):ip(p),use(1)    {}    ~Uptr(){delete ip;}}; class HasPtr{public:    HasPtr(int *p):ptr(new Uptr(p))    {}    HasPtr(const HasPtr& other){       ptr = other.ptr;       ++ptr->use;    }    HasPtr operator=(const HasPtr&other){       ++other.ptr->use;       if(--ptr->use==0)          delete ptr;       ptr = other.ptr;       return *this;     }     int& operator *()     { return *(ptr->ip);}     ~ HasPtr(){          if(--ptr->use==0)              delete ptr; //将调用伙伴类的析构函数      }private:   Uptr *ptr;//将int类型的指针封装到伙伴类中}; int main(){    HasPtr p1(new int(3));    HasPtr p2 = p1;    *p2 = 5;    cout<<*p1<<endl;//5    system("pause");    return 0;}



方案2:计数器封装到当前类中,但是计数器use必须采用指针,这样各个指向同一个指针的对象共享同一份空间,都可以去改这个计数器

/*copyright@ CNV && lsj*/ #include<iostream>using namespace std; class HasPtr{public:    HasPtr(int*p):ptr(p),use(new int(1))    {}    HasPtr(constHasPtr& other)    {        ptr= other.ptr;             use= other.use;        ++*use;    }    HasPtr&operator=(const HasPtr& other){                   ++*other.use;        if(--*use==0){            delete ptr;            delete use;         }                         ptr= other.ptr;         use= other.use;         return*this;     }     int& operator *()     {         return *ptr;     }     ~HasPtr()     {         if(--*use==0)         {             delete ptr;             delete use;         }     }private:    int *ptr;//所包含元素的指针     //一定要用指针,这样大家共用一份空间,都可以改写    int *use;};


策略五:写时复制计数

     有时候用户需要对象与对象之间的空间独立,但是每次都复制开销又很大。采用的策略是先不急着复制空间,拖到当另一个类要改写共享空间的时候,复制出来一份改写。

/*copyright@ CNV && lsj*/ #include<iostream>using namespace std; class HasPtr{public:    HasPtr(int*p):ptr(p),use(new int(1))    {}    HasPtr(constHasPtr& other){       ptr= other.ptr;       use= other.use;       ++*use;    }    HasPtr& operator=(const HasPtr& other){       ++*other.use;       if(--*use==0){           delete ptr;           delete use;        }                        ptr= other.ptr;        use= other.use;        return *this;    }    int& operator *()    {        return*ptr;    }    ~HasPtr()    {        if(--*use==0)        {           delete ptr;           delete use;        }    }    //这个接口要改写共享空间,此时复制一份改写    void setValue(intval)    {        //判断是不是只有当前对象持有共享空间        //如果是,则不用复制,直接改        if(*use!=1){            --*use;            use= new int(1);            ptr= new int(val);        }        *ptr= val;    }private:    int *ptr;//所包含元素的指针    //一定要用指针,这样大家共用一份空间,都可以改写    int *use;}; int main(){    HasPtr p1(newint(3));    HasPtr p2= p1;    p2.setValue(5);    cout<<*p1<<endl;//5    system("pause");    return 0;}



原创粉丝点击